about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs72
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs18
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs21
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs5
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs17
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs132
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs135
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs24
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs74
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs29
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs18
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs372
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs2
-rw-r--r--compiler/rustc_trait_selection/src/errors/note_and_explain.rs9
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs20
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs24
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs22
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs32
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs43
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/effects.rs138
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs198
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs200
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs297
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs6
41 files changed, 1172 insertions, 880 deletions
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 2c16672d786..b9acadc406e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -51,6 +51,7 @@ use std::path::PathBuf;
 use std::{cmp, fmt, iter};
 
 use rustc_abi::ExternAbi;
+use rustc_ast::join_path_syms;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{
     Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize,
@@ -73,7 +74,7 @@ use rustc_middle::ty::{
     TypeVisitableExt,
 };
 use rustc_span::def_id::LOCAL_CRATE;
-use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym};
+use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, Symbol, sym};
 use tracing::{debug, instrument};
 
 use crate::error_reporting::TypeErrCtxt;
@@ -82,9 +83,7 @@ use crate::infer;
 use crate::infer::relate::{self, RelateResult, TypeRelation};
 use crate::infer::{InferCtxt, InferCtxtExt as _, TypeTrace, ValuePairs};
 use crate::solve::deeply_normalize_for_diagnostics;
-use crate::traits::{
-    IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
-};
+use crate::traits::{MatchExpressionArmCause, ObligationCause, ObligationCauseCode};
 
 mod note_and_explain;
 mod suggest;
@@ -227,7 +226,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         struct AbsolutePathPrinter<'tcx> {
             tcx: TyCtxt<'tcx>,
-            segments: Vec<String>,
+            segments: Vec<Symbol>,
         }
 
         impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
@@ -255,7 +254,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
 
             fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
-                self.segments = vec![self.tcx.crate_name(cnum).to_string()];
+                self.segments = vec![self.tcx.crate_name(cnum)];
                 Ok(())
             }
             fn path_qualified(
@@ -281,7 +280,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 disambiguated_data: &DisambiguatedDefPathData,
             ) -> Result<(), PrintError> {
                 print_prefix(self)?;
-                self.segments.push(disambiguated_data.to_string());
+                self.segments.push(disambiguated_data.as_sym(true));
                 Ok(())
             }
             fn path_generic_args(
@@ -316,7 +315,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // known" by the same name, we use the "absolute path" which uses the original
                 // crate name instead.
                 let (expected, found) = if expected_str == found_str {
-                    (expected_abs.join("::"), found_abs.join("::"))
+                    (join_path_syms(&expected_abs), join_path_syms(&found_abs))
                 } else {
                     (expected_str.clone(), found_str.clone())
                 };
@@ -613,18 +612,28 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     }
                 }
             },
-            ObligationCauseCode::IfExpression(box IfExpressionCause {
-                then_id,
-                else_id,
-                then_ty,
-                else_ty,
-                outer_span,
-                ..
-            }) => {
-                let then_span = self.find_block_span_from_hir_id(then_id);
-                let else_span = self.find_block_span_from_hir_id(else_id);
-                if let hir::Node::Expr(e) = self.tcx.hir_node(else_id)
-                    && let hir::ExprKind::If(_cond, _then, None) = e.kind
+            ObligationCauseCode::IfExpression { expr_id, .. } => {
+                let hir::Node::Expr(&hir::Expr {
+                    kind: hir::ExprKind::If(cond_expr, then_expr, Some(else_expr)),
+                    span: expr_span,
+                    ..
+                }) = self.tcx.hir_node(expr_id)
+                else {
+                    return;
+                };
+                let then_span = self.find_block_span_from_hir_id(then_expr.hir_id);
+                let then_ty = self
+                    .typeck_results
+                    .as_ref()
+                    .expect("if expression only expected inside FnCtxt")
+                    .expr_ty(then_expr);
+                let else_span = self.find_block_span_from_hir_id(else_expr.hir_id);
+                let else_ty = self
+                    .typeck_results
+                    .as_ref()
+                    .expect("if expression only expected inside FnCtxt")
+                    .expr_ty(else_expr);
+                if let hir::ExprKind::If(_cond, _then, None) = else_expr.kind
                     && else_ty.is_unit()
                 {
                     // Account for `let x = if a { 1 } else if b { 2 };`
@@ -632,9 +641,32 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     err.note("consider adding an `else` block that evaluates to the expected type");
                 }
                 err.span_label(then_span, "expected because of this");
+
+                let outer_span = if self.tcx.sess.source_map().is_multiline(expr_span) {
+                    if then_span.hi() == expr_span.hi() || else_span.hi() == expr_span.hi() {
+                        // Point at condition only if either block has the same end point as
+                        // the whole expression, since that'll cause awkward overlapping spans.
+                        Some(expr_span.shrink_to_lo().to(cond_expr.peel_drop_temps().span))
+                    } else {
+                        Some(expr_span)
+                    }
+                } else {
+                    None
+                };
                 if let Some(sp) = outer_span {
                     err.span_label(sp, "`if` and `else` have incompatible types");
                 }
+
+                let then_id = if let hir::ExprKind::Block(then_blk, _) = then_expr.kind {
+                    then_blk.hir_id
+                } else {
+                    then_expr.hir_id
+                };
+                let else_id = if let hir::ExprKind::Block(else_blk, _) = else_expr.kind {
+                    else_blk.hir_id
+                } else {
+                    else_expr.hir_id
+                };
                 if let Some(subdiag) = self.suggest_remove_semi_or_return_binding(
                     Some(then_id),
                     then_ty,
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 bfef3340b32..1db05ced8d2 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
@@ -909,11 +909,11 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
                 }
             }
             (GenericArgKind::Const(inner_ct), TermKind::Const(target_ct)) => {
-                use ty::InferConst::*;
                 match (inner_ct.kind(), target_ct.kind()) {
-                    (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => {
-                        self.tecx.root_const_var(a_vid) == self.tecx.root_const_var(b_vid)
-                    }
+                    (
+                        ty::ConstKind::Infer(ty::InferConst::Var(a_vid)),
+                        ty::ConstKind::Infer(ty::InferConst::Var(b_vid)),
+                    ) => self.tecx.root_const_var(a_vid) == self.tecx.root_const_var(b_vid),
                     _ => false,
                 }
             }
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 139b2997136..8fe4ffebd86 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
@@ -75,7 +75,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
 
     fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
         match arg.kind {
-            hir::TyKind::BareFn(_) => {
+            hir::TyKind::FnPtr(_) => {
                 self.current_index.shift_in(1);
                 let _ = intravisit::walk_ty(self, arg);
                 self.current_index.shift_out(1);
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs
index e456ba0eda5..c0b4bdab849 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs
@@ -5,7 +5,6 @@ use rustc_span::Span;
 
 use crate::error_reporting::TypeErrCtxt;
 use crate::infer::RegionResolutionError;
-use crate::infer::RegionResolutionError::*;
 
 mod different_lifetimes;
 pub mod find_anon_type;
@@ -83,8 +82,10 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
 
     pub(super) fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
         match (&self.error, self.regions) {
-            (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), *sub, *sup)),
-            (Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {
+            (Some(RegionResolutionError::ConcreteFailure(origin, sub, sup)), None) => {
+                Some((origin.span(), *sub, *sup))
+            }
+            (Some(RegionResolutionError::SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {
                 Some((origin.span(), *sub, *sup))
             }
             (None, Some((span, sub, sup))) => Some((span, sub, sup)),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs
index aa7935a29f0..73a04d78519 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs
@@ -2,8 +2,6 @@
 //! where one region is named and the other is anonymous.
 
 use rustc_errors::Diag;
-use rustc_middle::ty;
-use rustc_span::kw;
 use tracing::debug;
 
 use crate::error_reporting::infer::nice_region_error::NiceRegionError;
@@ -27,12 +25,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         // only introduced anonymous regions in parameters) as well as a
         // version new_ty of its type where the anonymous region is replaced
         // with the named one.
-        let (named, anon, anon_param_info, region_info) = if sub.has_name()
+        let (named, anon, anon_param_info, region_info) = if sub.is_named(self.tcx())
             && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sup)
             && let Some(anon_param_info) = self.find_param_with_region(sup, sub)
         {
             (sub, sup, anon_param_info, region_info)
-        } else if sup.has_name()
+        } else if sup.is_named(self.tcx())
             && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sub)
             && let Some(anon_param_info) = self.find_param_with_region(sub, sup)
         {
@@ -58,14 +56,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let scope_def_id = region_info.scope;
         let is_impl_item = region_info.is_impl_item;
 
-        match anon_param_info.kind {
-            ty::LateParamRegionKind::Named(_, kw::UnderscoreLifetime)
-            | ty::LateParamRegionKind::Anon(_) => {}
-            _ => {
-                /* not an anonymous region */
-                debug!("try_report_named_anon_conflict: not an anonymous region");
-                return None;
-            }
+        if anon_param_info.kind.is_named(self.tcx()) {
+            /* not an anonymous region */
+            debug!("try_report_named_anon_conflict: not an anonymous region");
+            return None;
         }
 
         if is_impl_item {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
index 5056161e117..64fc365c44a 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
@@ -164,7 +164,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
                 sub_region @ Region(Interned(RePlaceholder(_), _)),
                 sup_region,
             )) => self.try_report_trait_placeholder_mismatch(
-                (!sup_region.has_name()).then_some(*sup_region),
+                (!sup_region.is_named(self.tcx())).then_some(*sup_region),
                 cause,
                 Some(*sub_region),
                 None,
@@ -176,7 +176,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
                 sub_region,
                 sup_region @ Region(Interned(RePlaceholder(_), _)),
             )) => self.try_report_trait_placeholder_mismatch(
-                (!sub_region.has_name()).then_some(*sub_region),
+                (!sub_region.is_named(self.tcx())).then_some(*sub_region),
                 cause,
                 None,
                 Some(*sup_region),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs
index 7fcd3c847e3..3bab09bc587 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::intern::Interned;
 use rustc_errors::Diag;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, RePlaceholder, Region};
 
 use crate::error_reporting::infer::nice_region_error::NiceRegionError;
@@ -28,20 +29,22 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
                 )),
             )) => {
                 let span = *span;
-                let (sub_span, sub_symbol) = match sub_name {
-                    ty::BoundRegionKind::Named(def_id, symbol) => {
-                        (Some(self.tcx().def_span(def_id)), Some(symbol))
+                let (sub_span, sub_symbol) = match *sub_name {
+                    ty::BoundRegionKind::Named(def_id) => {
+                        (Some(self.tcx().def_span(def_id)), Some(self.tcx().item_name(def_id)))
                     }
                     ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => (None, None),
+                    ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"),
                 };
-                let (sup_span, sup_symbol) = match sup_name {
-                    ty::BoundRegionKind::Named(def_id, symbol) => {
-                        (Some(self.tcx().def_span(def_id)), Some(symbol))
+                let (sup_span, sup_symbol) = match *sup_name {
+                    ty::BoundRegionKind::Named(def_id) => {
+                        (Some(self.tcx().def_span(def_id)), Some(self.tcx().item_name(def_id)))
                     }
                     ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => (None, None),
+                    ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"),
                 };
                 let diag = match (sub_span, sup_span, sub_symbol, sup_symbol) {
-                    (Some(sub_span), Some(sup_span), Some(&sub_symbol), Some(&sup_symbol)) => {
+                    (Some(sub_span), Some(sup_span), Some(sub_symbol), Some(sup_symbol)) => {
                         PlaceholderRelationLfNotSatisfied::HasBoth {
                             span,
                             sub_span,
@@ -51,7 +54,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
                             note: (),
                         }
                     }
-                    (Some(sub_span), Some(sup_span), _, Some(&sup_symbol)) => {
+                    (Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => {
                         PlaceholderRelationLfNotSatisfied::HasSup {
                             span,
                             sub_span,
@@ -60,7 +63,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
                             note: (),
                         }
                     }
-                    (Some(sub_span), Some(sup_span), Some(&sub_symbol), _) => {
+                    (Some(sub_span), Some(sup_span), Some(sub_symbol), _) => {
                         PlaceholderRelationLfNotSatisfied::HasSub {
                             span,
                             sub_span,
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 eaa06d8e8b0..3edc365c886 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
@@ -45,7 +45,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let return_sp = sub_origin.span();
         let param = self.find_param_with_region(*sup_r, *sub_r)?;
         let simple_ident = param.param.pat.simple_ident();
-        let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
+        let lifetime_name =
+            if sup_r.is_named(self.tcx()) { sup_r.to_string() } else { "'_".to_owned() };
 
         let (mention_influencer, influencer_point) =
             if sup_origin.span().overlaps(param.param_ty_span) {
@@ -99,7 +100,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             // 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),
 
-            has_lifetime: sup_r.has_name(),
+            has_lifetime: sup_r.is_named(self.tcx()),
             lifetime: lifetime_name.clone(),
             has_param_name: simple_ident.is_some(),
             param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(),
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 b66bd2c6ab7..772a7f01332 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
@@ -5,6 +5,7 @@ use rustc_hir::def::{Namespace, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{Visitor, walk_ty};
 use rustc_hir::{self as hir, AmbigArg};
+use rustc_infer::infer::SubregionOrigin;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::error::ExpectedFound;
@@ -16,7 +17,7 @@ use tracing::debug;
 use crate::error_reporting::infer::nice_region_error::NiceRegionError;
 use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted;
 use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
-use crate::infer::{RegionResolutionError, Subtype, ValuePairs};
+use crate::infer::{RegionResolutionError, ValuePairs};
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
@@ -32,7 +33,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             _sup,
             _,
         ) = error.clone()
-            && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
+            && let (SubregionOrigin::Subtype(sup_trace), SubregionOrigin::Subtype(sub_trace)) =
+                (&sup_origin, &sub_origin)
             && let &ObligationCauseCode::CompareImplItem { trait_item_def_id, .. } =
                 sub_trace.cause.code()
             && sub_trace.values == sup_trace.values
@@ -58,14 +60,15 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         // Mark all unnamed regions in the type with a number.
         // This diagnostic is called in response to lifetime errors, so be informative.
         struct HighlightBuilder<'tcx> {
+            tcx: TyCtxt<'tcx>,
             highlight: RegionHighlightMode<'tcx>,
             counter: usize,
         }
 
         impl<'tcx> HighlightBuilder<'tcx> {
-            fn build(sig: ty::PolyFnSig<'tcx>) -> RegionHighlightMode<'tcx> {
+            fn build(tcx: TyCtxt<'tcx>, sig: ty::PolyFnSig<'tcx>) -> RegionHighlightMode<'tcx> {
                 let mut builder =
-                    HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 };
+                    HighlightBuilder { tcx, highlight: RegionHighlightMode::default(), counter: 1 };
                 sig.visit_with(&mut builder);
                 builder.highlight
             }
@@ -73,15 +76,15 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 
         impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HighlightBuilder<'tcx> {
             fn visit_region(&mut self, r: ty::Region<'tcx>) {
-                if !r.has_name() && self.counter <= 3 {
+                if !r.is_named(self.tcx) && self.counter <= 3 {
                     self.highlight.highlighting_region(r, self.counter);
                     self.counter += 1;
                 }
             }
         }
 
-        let expected_highlight = HighlightBuilder::build(expected);
         let tcx = self.cx.tcx;
+        let expected_highlight = HighlightBuilder::build(tcx, expected);
         let expected = Highlighted {
             highlight: expected_highlight,
             ns: Namespace::TypeNS,
@@ -89,7 +92,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             value: expected,
         }
         .to_string();
-        let found_highlight = HighlightBuilder::build(found);
+        let found_highlight = HighlightBuilder::build(tcx, found);
         let found =
             Highlighted { highlight: found_highlight, ns: Namespace::TypeNS, tcx, value: found }
                 .to_string();
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 4a71ab4e06a..5f2aab38c31 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
@@ -46,7 +46,7 @@ pub fn find_param_with_region<'tcx>(
         ty::ReLateParam(late_param) => (late_param.scope, late_param.kind),
         ty::ReEarlyParam(ebr) => {
             let region_def = tcx.generics_of(generic_param_scope).region_param(ebr, tcx).def_id;
-            (tcx.parent(region_def), ty::LateParamRegionKind::Named(region_def, ebr.name))
+            (tcx.parent(region_def), ty::LateParamRegionKind::Named(region_def))
         }
         _ => return None, // not a free region
     };
@@ -144,7 +144,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         // We are only checking is any region meets the condition so order doesn't matter
         #[allow(rustc::potential_query_instability)]
         late_bound_regions.iter().any(|r| match *r {
-            ty::BoundRegionKind::Named(def_id, _) => def_id == region_def_id,
+            ty::BoundRegionKind::Named(def_id) => def_id == region_def_id,
             _ => false,
         })
     }
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 be508c8cee1..db35c988bf7 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
@@ -1,3 +1,4 @@
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{Diag, MultiSpan, pluralize};
 use rustc_hir as hir;
@@ -8,7 +9,7 @@ use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::print::{FmtPrinter, Printer};
 use rustc_middle::ty::{self, Ty, suggest_constraining_type_param};
 use rustc_span::def_id::DefId;
-use rustc_span::{BytePos, Span, Symbol, sym};
+use rustc_span::{BytePos, Span, Symbol};
 use tracing::debug;
 
 use crate::error_reporting::TypeErrCtxt;
@@ -353,26 +354,6 @@ impl<T> Trait<T> for X {
                             ));
                         }
                     }
-                    (ty::Dynamic(t, _, ty::DynKind::DynStar), _)
-                        if let Some(def_id) = t.principal_def_id() =>
-                    {
-                        let mut has_matching_impl = false;
-                        tcx.for_each_relevant_impl(def_id, values.found, |did| {
-                            if DeepRejectCtxt::relate_rigid_infer(tcx)
-                                .types_may_unify(values.found, tcx.type_of(did).skip_binder())
-                            {
-                                has_matching_impl = true;
-                            }
-                        });
-                        if has_matching_impl {
-                            let trait_name = tcx.item_name(def_id);
-                            diag.help(format!(
-                                "`{}` implements `{trait_name}`, `#[feature(dyn_star)]` is likely \
-                                 not enabled; that feature it is currently incomplete",
-                                values.found,
-                            ));
-                        }
-                    }
                     (_, ty::Alias(ty::Opaque, opaque_ty))
                     | (ty::Alias(ty::Opaque, opaque_ty), _) => {
                         if opaque_ty.def_id.is_local()
@@ -420,19 +401,33 @@ impl<T> Trait<T> for X {
                         }
                         // If two if arms can be coerced to a trait object, provide a structured
                         // suggestion.
-                        let ObligationCauseCode::IfExpression(cause) = cause.code() else {
+                        let ObligationCauseCode::IfExpression { expr_id, .. } = cause.code() else {
                             return;
                         };
-                        let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id) else {
-                            return;
-                        };
-                        let Some(then) = blk.expr else {
-                            return;
-                        };
-                        let hir::Node::Block(blk) = self.tcx.hir_node(cause.else_id) else {
-                            return;
-                        };
-                        let Some(else_) = blk.expr else {
+                        let hir::Node::Expr(&hir::Expr {
+                            kind:
+                                hir::ExprKind::If(
+                                    _,
+                                    &hir::Expr {
+                                        kind:
+                                            hir::ExprKind::Block(
+                                                &hir::Block { expr: Some(then), .. },
+                                                _,
+                                            ),
+                                        ..
+                                    },
+                                    Some(&hir::Expr {
+                                        kind:
+                                            hir::ExprKind::Block(
+                                                &hir::Block { expr: Some(else_), .. },
+                                                _,
+                                            ),
+                                        ..
+                                    }),
+                                ),
+                            ..
+                        }) = self.tcx.hir_node(*expr_id)
+                        else {
                             return;
                         };
                         let expected = match values.found.kind() {
@@ -486,8 +481,10 @@ impl<T> Trait<T> for X {
                         }
                     }
                     (ty::Adt(_, _), ty::Adt(def, args))
-                        if let ObligationCauseCode::IfExpression(cause) = cause.code()
-                            && let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id)
+                        if let ObligationCauseCode::IfExpression { expr_id, .. } = cause.code()
+                            && let hir::Node::Expr(if_expr) = self.tcx.hir_node(*expr_id)
+                            && let hir::ExprKind::If(_, then_expr, _) = if_expr.kind
+                            && let hir::ExprKind::Block(blk, _) = then_expr.kind
                             && let Some(then) = blk.expr
                             && def.is_box()
                             && let boxed_ty = args.type_at(0)
@@ -539,8 +536,7 @@ 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 = find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TargetFeature(.., span) => *span);
                 diag.note(
                     "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
                 );
@@ -845,54 +841,32 @@ fn foo(&self) -> Self::T { String::new() }
 
         let param_env = tcx.param_env(body_owner_def_id);
 
-        match item {
-            hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. }) => {
-                // FIXME: account for `#![feature(specialization)]`
-                for item in &items[..] {
-                    match item.kind {
-                        hir::AssocItemKind::Type => {
-                            // FIXME: account for returning some type in a trait fn impl that has
-                            // an assoc type as a return type (#72076).
-                            if let hir::Defaultness::Default { has_value: true } =
-                                tcx.defaultness(item.id.owner_id)
-                            {
-                                let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
-                                if self.infcx.can_eq(param_env, assoc_ty, found) {
-                                    diag.span_label(
-                                        item.span,
-                                        "associated type defaults can't be assumed inside the \
-                                            trait defining them",
-                                    );
-                                    return true;
-                                }
-                            }
+        if let DefKind::Trait | DefKind::Impl { .. } = tcx.def_kind(parent_id) {
+            let assoc_items = tcx.associated_items(parent_id);
+            // FIXME: account for `#![feature(specialization)]`
+            for assoc_item in assoc_items.in_definition_order() {
+                if assoc_item.is_type()
+                    // FIXME: account for returning some type in a trait fn impl that has
+                    // an assoc type as a return type (#72076).
+                    && let hir::Defaultness::Default { has_value: true } = assoc_item.defaultness(tcx)
+                    && let assoc_ty = tcx.type_of(assoc_item.def_id).instantiate_identity()
+                    && self.infcx.can_eq(param_env, assoc_ty, found)
+                {
+                    let msg = match assoc_item.container {
+                        ty::AssocItemContainer::Trait => {
+                            "associated type defaults can't be assumed inside the \
+                                            trait defining them"
                         }
-                        _ => {}
-                    }
-                }
-            }
-            hir::Node::Item(hir::Item {
-                kind: hir::ItemKind::Impl(hir::Impl { items, .. }),
-                ..
-            }) => {
-                for item in &items[..] {
-                    if let hir::AssocItemKind::Type = item.kind {
-                        let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
-                        if let hir::Defaultness::Default { has_value: true } =
-                            tcx.defaultness(item.id.owner_id)
-                            && self.infcx.can_eq(param_env, assoc_ty, found)
-                        {
-                            diag.span_label(
-                                item.span,
-                                "associated type is `default` and may be overridden",
-                            );
-                            return true;
+                        ty::AssocItemContainer::Impl => {
+                            "associated type is `default` and may be overridden"
                         }
-                    }
+                    };
+                    diag.span_label(tcx.def_span(assoc_item.def_id), msg);
+                    return true;
                 }
             }
-            _ => {}
         }
+
         false
     }
 
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 5c669678ccc..f3441a8d72a 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -27,7 +27,10 @@ use crate::errors::{
 };
 use crate::fluent_generated as fluent;
 use crate::infer::region_constraints::GenericKind;
-use crate::infer::{self, InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin};
+use crate::infer::{
+    BoundRegionConversionTime, InferCtxt, RegionResolutionError, RegionVariableOrigin,
+    SubregionOrigin,
+};
 
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     pub fn report_region_errors(
@@ -219,21 +222,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
     pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) {
         match *origin {
-            infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
+            SubregionOrigin::Subtype(ref trace) => RegionOriginNote::WithRequirement {
                 span: trace.cause.span,
                 requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
                 expected_found: self.values_str(trace.values, &trace.cause, err.long_ty_path()),
             }
             .add_to_diag(err),
-            infer::Reborrow(span) => {
+            SubregionOrigin::Reborrow(span) => {
                 RegionOriginNote::Plain { span, msg: fluent::trait_selection_reborrow }
                     .add_to_diag(err)
             }
-            infer::RelateObjectBound(span) => {
+            SubregionOrigin::RelateObjectBound(span) => {
                 RegionOriginNote::Plain { span, msg: fluent::trait_selection_relate_object_bound }
                     .add_to_diag(err);
             }
-            infer::ReferenceOutlivesReferent(ty, span) => {
+            SubregionOrigin::ReferenceOutlivesReferent(ty, span) => {
                 RegionOriginNote::WithName {
                     span,
                     msg: fluent::trait_selection_reference_outlives_referent,
@@ -242,7 +245,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }
                 .add_to_diag(err);
             }
-            infer::RelateParamBound(span, ty, opt_span) => {
+            SubregionOrigin::RelateParamBound(span, ty, opt_span) => {
                 RegionOriginNote::WithName {
                     span,
                     msg: fluent::trait_selection_relate_param_bound,
@@ -258,24 +261,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     .add_to_diag(err);
                 }
             }
-            infer::RelateRegionParamBound(span, _) => {
+            SubregionOrigin::RelateRegionParamBound(span, _) => {
                 RegionOriginNote::Plain {
                     span,
                     msg: fluent::trait_selection_relate_region_param_bound,
                 }
                 .add_to_diag(err);
             }
-            infer::CompareImplItemObligation { span, .. } => {
+            SubregionOrigin::CompareImplItemObligation { span, .. } => {
                 RegionOriginNote::Plain {
                     span,
                     msg: fluent::trait_selection_compare_impl_item_obligation,
                 }
                 .add_to_diag(err);
             }
-            infer::CheckAssociatedTypeBounds { ref parent, .. } => {
+            SubregionOrigin::CheckAssociatedTypeBounds { ref parent, .. } => {
                 self.note_region_origin(err, parent);
             }
-            infer::AscribeUserTypeProvePredicate(span) => {
+            SubregionOrigin::AscribeUserTypeProvePredicate(span) => {
                 RegionOriginNote::Plain {
                     span,
                     msg: fluent::trait_selection_ascribe_user_type_prove_predicate,
@@ -293,7 +296,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         sup: Region<'tcx>,
     ) -> Diag<'a> {
         let mut err = match origin {
-            infer::Subtype(box trace) => {
+            SubregionOrigin::Subtype(box trace) => {
                 let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
                 let mut err = self.report_and_explain_type_error(
                     trace,
@@ -347,7 +350,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }
                 err
             }
-            infer::Reborrow(span) => {
+            SubregionOrigin::Reborrow(span) => {
                 let reference_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
                     generic_param_scope,
@@ -369,7 +372,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     notes: reference_valid.into_iter().chain(content_valid).collect(),
                 })
             }
-            infer::RelateObjectBound(span) => {
+            SubregionOrigin::RelateObjectBound(span) => {
                 let object_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
                     generic_param_scope,
@@ -391,7 +394,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     notes: object_valid.into_iter().chain(pointer_valid).collect(),
                 })
             }
-            infer::RelateParamBound(span, ty, opt_span) => {
+            SubregionOrigin::RelateParamBound(span, ty, opt_span) => {
                 let prefix = match sub.kind() {
                     ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy,
                     _ => note_and_explain::PrefixKind::TypeOutlive,
@@ -415,7 +418,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     note,
                 })
             }
-            infer::RelateRegionParamBound(span, ty) => {
+            SubregionOrigin::RelateRegionParamBound(span, ty) => {
                 let param_instantiated = note_and_explain::RegionExplanation::new(
                     self.tcx,
                     generic_param_scope,
@@ -457,7 +460,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
                 })
             }
-            infer::ReferenceOutlivesReferent(ty, span) => {
+            SubregionOrigin::ReferenceOutlivesReferent(ty, span) => {
                 let pointer_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
                     generic_param_scope,
@@ -480,7 +483,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     notes: pointer_valid.into_iter().chain(data_valid).collect(),
                 })
             }
-            infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
+            SubregionOrigin::CompareImplItemObligation {
+                span,
+                impl_item_def_id,
+                trait_item_def_id,
+            } => {
                 let mut err = self.report_extra_impl_obligation(
                     span,
                     impl_item_def_id,
@@ -499,7 +506,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }
                 err
             }
-            infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
+            SubregionOrigin::CheckAssociatedTypeBounds {
+                impl_item_def_id,
+                trait_item_def_id,
+                parent,
+            } => {
                 let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup);
 
                 // Don't mention the item name if it's an RPITIT, since that'll just confuse
@@ -520,7 +531,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 );
                 err
             }
-            infer::AscribeUserTypeProvePredicate(span) => {
+            SubregionOrigin::AscribeUserTypeProvePredicate(span) => {
                 let instantiated = note_and_explain::RegionExplanation::new(
                     self.tcx,
                     generic_param_scope,
@@ -618,7 +629,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         // I can't think how to do better than this right now. -nikomatsakis
         debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
         match placeholder_origin {
-            infer::Subtype(box ref trace)
+            SubregionOrigin::Subtype(box ref trace)
                 if matches!(
                     &trace.cause.code().peel_derives(),
                     ObligationCauseCode::WhereClause(..)
@@ -648,7 +659,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     )
                 }
             }
-            infer::Subtype(box trace) => {
+            SubregionOrigin::Subtype(box trace) => {
                 let terr = TypeError::RegionsPlaceholderMismatch;
                 return self.report_and_explain_type_error(
                     trace,
@@ -702,14 +713,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
 
         let labeled_user_string = match bound_kind {
-            GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
-            GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
-            GenericKind::Alias(ref p) => match p.kind(self.tcx) {
+            GenericKind::Param(_) => format!("the parameter type `{bound_kind}`"),
+            GenericKind::Placeholder(_) => format!("the placeholder type `{bound_kind}`"),
+            GenericKind::Alias(p) => match p.kind(self.tcx) {
                 ty::Projection | ty::Inherent => {
-                    format!("the associated type `{p}`")
+                    format!("the associated type `{bound_kind}`")
                 }
-                ty::Free => format!("the type alias `{p}`"),
-                ty::Opaque => format!("the opaque type `{p}`"),
+                ty::Free => format!("the type alias `{bound_kind}`"),
+                ty::Opaque => format!("the opaque type `{bound_kind}`"),
             },
         };
 
@@ -718,7 +729,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             .dcx()
             .struct_span_err(span, format!("{labeled_user_string} may not live long enough"));
         err.code(match sub.kind() {
-            ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => E0309,
+            ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.is_named(self.tcx) => E0309,
             ty::ReStatic => E0310,
             _ => E0311,
         });
@@ -744,7 +755,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 || (bound_kind, sub).has_placeholders()
                 || !bound_kind.is_suggestable(self.tcx, false)
             {
-                let lt_name = sub.get_name_or_anon().to_string();
+                let lt_name = sub.get_name_or_anon(self.tcx).to_string();
                 err.help(format!("{msg} `{bound_kind}: {lt_name}`..."));
                 break 'suggestion;
             }
@@ -864,13 +875,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
         }
 
-        let (lifetime_def_id, lifetime_scope) = match self
-            .tcx
-            .is_suitable_region(generic_param_scope, lifetime)
-        {
-            Some(info) if !lifetime.has_name() => (info.region_def_id.expect_local(), info.scope),
-            _ => return lifetime.get_name_or_anon().to_string(),
-        };
+        let (lifetime_def_id, lifetime_scope) =
+            match self.tcx.is_suitable_region(generic_param_scope, lifetime) {
+                Some(info) if !lifetime.is_named(self.tcx) => {
+                    (info.region_def_id.expect_local(), info.scope)
+                }
+                _ => return lifetime.get_name_or_anon(self.tcx).to_string(),
+            };
 
         let new_lt = {
             let generics = self.tcx.generics_of(lifetime_scope);
@@ -884,7 +895,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             // consider late-bound lifetimes ...
             used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(
                 |p| match p {
-                    ty::BoundVariableKind::Region(lt) => lt.get_name(),
+                    ty::BoundVariableKind::Region(lt) => lt.get_name(self.tcx),
                     _ => None,
                 },
             ));
@@ -945,8 +956,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
         debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
 
-        if let infer::Subtype(ref sup_trace) = sup_origin
-            && let infer::Subtype(ref sub_trace) = sub_origin
+        if let SubregionOrigin::Subtype(ref sup_trace) = sup_origin
+            && let SubregionOrigin::Subtype(ref sub_trace) = sub_origin
             && let Some((sup_expected, sup_found)) =
                 self.values_str(sup_trace.values, &sup_trace.cause, err.long_ty_path())
             && let Some((sub_expected, sub_found)) =
@@ -995,7 +1006,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> {
         let br_string = |br: ty::BoundRegionKind| {
             let mut s = match br {
-                ty::BoundRegionKind::Named(_, name) => name.to_string(),
+                ty::BoundRegionKind::Named(def_id) => self.tcx.item_name(def_id).to_string(),
                 _ => String::new(),
             };
             if !s.is_empty() {
@@ -1004,30 +1015,38 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             s
         };
         let var_description = match var_origin {
-            infer::MiscVariable(_) => String::new(),
-            infer::PatternRegion(_) => " for pattern".to_string(),
-            infer::BorrowRegion(_) => " for borrow expression".to_string(),
-            infer::Autoref(_) => " for autoref".to_string(),
-            infer::Coercion(_) => " for automatic coercion".to_string(),
-            infer::BoundRegion(_, br, infer::FnCall) => {
+            RegionVariableOrigin::Misc(_) => String::new(),
+            RegionVariableOrigin::PatternRegion(_) => " for pattern".to_string(),
+            RegionVariableOrigin::BorrowRegion(_) => " for borrow expression".to_string(),
+            RegionVariableOrigin::Autoref(_) => " for autoref".to_string(),
+            RegionVariableOrigin::Coercion(_) => " for automatic coercion".to_string(),
+            RegionVariableOrigin::BoundRegion(_, br, BoundRegionConversionTime::FnCall) => {
                 format!(" for lifetime parameter {}in function call", br_string(br))
             }
-            infer::BoundRegion(_, br, infer::HigherRankedType) => {
+            RegionVariableOrigin::BoundRegion(
+                _,
+                br,
+                BoundRegionConversionTime::HigherRankedType,
+            ) => {
                 format!(" for lifetime parameter {}in generic type", br_string(br))
             }
-            infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
+            RegionVariableOrigin::BoundRegion(
+                _,
+                br,
+                BoundRegionConversionTime::AssocTypeProjection(def_id),
+            ) => format!(
                 " for lifetime parameter {}in trait containing associated type `{}`",
                 br_string(br),
                 self.tcx.associated_item(def_id).name()
             ),
-            infer::RegionParameterDefinition(_, name) => {
+            RegionVariableOrigin::RegionParameterDefinition(_, name) => {
                 format!(" for lifetime parameter `{name}`")
             }
-            infer::UpvarRegion(ref upvar_id, _) => {
+            RegionVariableOrigin::UpvarRegion(ref upvar_id, _) => {
                 let var_name = self.tcx.hir_name(upvar_id.var_path.hir_id);
                 format!(" for capture of `{var_name}` by closure")
             }
-            infer::Nll(..) => bug!("NLL variable found in lexical phase"),
+            RegionVariableOrigin::Nll(..) => bug!("NLL variable found in lexical phase"),
         };
 
         struct_span_code_err!(
@@ -1090,7 +1109,7 @@ fn msg_span_from_named_region<'tcx>(
         ty::ReEarlyParam(br) => {
             let param_def_id = tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id;
             let span = tcx.def_span(param_def_id);
-            let text = if br.has_name() {
+            let text = if br.is_named() {
                 format!("the lifetime `{}` as defined here", br.name)
             } else {
                 "the anonymous lifetime as defined here".to_string()
@@ -1098,13 +1117,14 @@ fn msg_span_from_named_region<'tcx>(
             (text, Some(span))
         }
         ty::ReLateParam(ref fr) => {
-            if !fr.kind.is_named()
+            if !fr.kind.is_named(tcx)
                 && let Some((ty, _)) = find_anon_type(tcx, generic_param_scope, region)
             {
                 ("the anonymous lifetime defined here".to_string(), Some(ty.span))
             } else {
                 match fr.kind {
-                    ty::LateParamRegionKind::Named(param_def_id, name) => {
+                    ty::LateParamRegionKind::Named(param_def_id) => {
+                        let name = tcx.item_name(param_def_id);
                         let span = tcx.def_span(param_def_id);
                         let text = if name == kw::UnderscoreLifetime {
                             "the anonymous lifetime as defined here".to_string()
@@ -1126,9 +1146,12 @@ fn msg_span_from_named_region<'tcx>(
         }
         ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
         ty::RePlaceholder(ty::PlaceholderRegion {
-            bound: ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id, name), .. },
+            bound: ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id), .. },
             ..
-        }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))),
+        }) => (
+            format!("the lifetime `{}` as defined here", tcx.item_name(def_id)),
+            Some(tcx.def_span(def_id)),
+        ),
         ty::RePlaceholder(ty::PlaceholderRegion {
             bound: ty::BoundRegion { kind: ty::BoundRegionKind::Anon, .. },
             ..
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 3804c13acce..c0daf08ce07 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -8,9 +8,7 @@ use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::{MatchSource, Node};
-use rustc_middle::traits::{
-    IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
-};
+use rustc_middle::traits::{MatchExpressionArmCause, ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
@@ -196,8 +194,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             (Some(exp), Some(found)) if self.same_type_modulo_infer(exp, found) => match cause
                 .code()
             {
-                ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
-                    let then_span = self.find_block_span_from_hir_id(*then_id);
+                ObligationCauseCode::IfExpression { expr_id, .. } => {
+                    let hir::Node::Expr(hir::Expr {
+                        kind: hir::ExprKind::If(_, then_expr, _), ..
+                    }) = self.tcx.hir_node(*expr_id)
+                    else {
+                        return;
+                    };
+                    let then_span = self.find_block_span_from_hir_id(then_expr.hir_id);
                     Some(ConsiderAddingAwait::BothFuturesSugg {
                         first: then_span.shrink_to_hi(),
                         second: exp_span.shrink_to_hi(),
@@ -232,8 +236,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         span: then_span.shrink_to_hi(),
                     })
                 }
-                ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
-                    let then_span = self.find_block_span_from_hir_id(*then_id);
+                ObligationCauseCode::IfExpression { expr_id, .. } => {
+                    let hir::Node::Expr(hir::Expr {
+                        kind: hir::ExprKind::If(_, then_expr, _), ..
+                    }) = self.tcx.hir_node(*expr_id)
+                    else {
+                        return;
+                    };
+                    let then_span = self.find_block_span_from_hir_id(then_expr.hir_id);
                     Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() })
                 }
                 ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
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 39f115ce0cd..98f67257fd1 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -4,7 +4,7 @@ use rustc_errors::{Applicability, Diag, E0283, E0284, E0790, MultiSpan, struct_s
 use rustc_hir as hir;
 use rustc_hir::LangItem;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
 use rustc_hir::intravisit::Visitor as _;
 use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt};
 use rustc_infer::traits::util::elaborate;
@@ -12,6 +12,7 @@ use rustc_infer::traits::{
     Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation,
 };
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _};
+use rustc_session::parse::feature_err_unstable_feature_bound;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
 use tracing::{debug, instrument};
 
@@ -128,19 +129,26 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>(
         },
     );
 
-    let predicates =
-        tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx);
-    for (pred, span) in elaborate(tcx, predicates.into_iter()) {
-        let kind = pred.kind();
-        if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder()
-            && param_env_candidate_may_apply(kind.rebind(trait_pred))
-        {
-            if kind.rebind(trait_pred.trait_ref)
-                == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id()))
+    // If our `body_id` has been set (and isn't just from a dummy obligation cause),
+    // then try to look for a param-env clause that would apply. The way we compute
+    // this is somewhat manual, since we need the spans, so we elaborate this directly
+    // from `predicates_of` rather than actually looking at the param-env which
+    // otherwise would be more appropriate.
+    let body_id = obligation.cause.body_id;
+    if body_id != CRATE_DEF_ID {
+        let predicates = tcx.predicates_of(body_id.to_def_id()).instantiate_identity(tcx);
+        for (pred, span) in elaborate(tcx, predicates.into_iter()) {
+            let kind = pred.kind();
+            if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder()
+                && param_env_candidate_may_apply(kind.rebind(trait_pred))
             {
-                ambiguities.push(CandidateSource::ParamEnv(tcx.def_span(trait_pred.def_id())))
-            } else {
-                ambiguities.push(CandidateSource::ParamEnv(span))
+                if kind.rebind(trait_pred.trait_ref)
+                    == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id()))
+                {
+                    ambiguities.push(CandidateSource::ParamEnv(tcx.def_span(trait_pred.def_id())))
+                } else {
+                    ambiguities.push(CandidateSource::ParamEnv(span))
+                }
             }
         }
     }
@@ -355,7 +363,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         && self.tcx.trait_of_item(*item_id) == Some(*trait_id)
                         && let None = self.tainted_by_errors()
                     {
-                        let (verb, noun) = match self.tcx.associated_item(item_id).kind {
+                        let assoc_item = self.tcx.associated_item(item_id);
+                        let (verb, noun) = match assoc_item.kind {
                             ty::AssocKind::Const { .. } => ("refer to the", "constant"),
                             ty::AssocKind::Fn { .. } => ("call", "function"),
                             // This is already covered by E0223, but this following single match
@@ -374,17 +383,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         );
                         err.code(E0790);
 
-                        if let Some(local_def_id) = data.trait_ref.def_id.as_local()
-                            && let hir::Node::Item(hir::Item {
-                                kind: hir::ItemKind::Trait(_, _, trait_ident, _, _, trait_item_refs),
-                                ..
-                            }) = self.tcx.hir_node_by_def_id(local_def_id)
-                            && let Some(method_ref) = trait_item_refs
-                                .iter()
-                                .find(|item_ref| item_ref.ident == *assoc_item_ident)
-                        {
+                        if item_id.is_local() {
+                            let trait_ident = self.tcx.item_name(*trait_id);
                             err.span_label(
-                                method_ref.span,
+                                self.tcx.def_span(*item_id),
                                 format!("`{trait_ident}::{assoc_item_ident}` defined here"),
                             );
                         }
@@ -610,6 +612,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 )
                 .with_span_label(span, format!("cannot normalize `{alias}`"))
             }
+            ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(sym)) => {
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+
+                let mut err;
+
+                if self.tcx.features().staged_api() {
+                    err = self.dcx().struct_span_err(
+                        span,
+                        format!("unstable feature `{sym}` is used without being enabled."),
+                    );
+
+                    err.help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`"));
+                } else {
+                    err = feature_err_unstable_feature_bound(
+                        &self.tcx.sess,
+                        sym,
+                        span,
+                        format!("use of unstable library feature `{sym}`"),
+                    );
+                }
+                err
+            }
 
             _ => {
                 if let Some(e) = self.tainted_by_errors() {
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 0c88bd3dcbc..1ac309da101 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
@@ -47,8 +47,8 @@ use crate::infer::{self, InferCtxt, InferCtxtExt as _};
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use crate::traits::{
     MismatchedProjectionTypes, NormalizeExt, Obligation, ObligationCause, ObligationCauseCode,
-    ObligationCtxt, Overflow, PredicateObligation, SelectionContext, SelectionError,
-    SignatureMismatch, TraitDynIncompatible, elaborate, specialization_graph,
+    ObligationCtxt, PredicateObligation, SelectionContext, SelectionError, elaborate,
+    specialization_graph,
 };
 
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
@@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     | ty::PredicateKind::ConstEquate { .. }
                     // Ambiguous predicates should never error
                     | ty::PredicateKind::Ambiguous
+                    // We never return Err when proving UnstableFeature goal.
+                    | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature{ .. })
                     | ty::PredicateKind::NormalizesTo { .. }
                     | ty::PredicateKind::AliasRelate { .. }
                     | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => {
@@ -659,7 +661,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }
             }
 
-            SignatureMismatch(box SignatureMismatchData {
+            SelectionError::SignatureMismatch(box SignatureMismatchData {
                 found_trait_ref,
                 expected_trait_ref,
                 terr: terr @ TypeError::CyclicTy(_),
@@ -669,7 +671,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 expected_trait_ref,
                 terr,
             ),
-            SignatureMismatch(box SignatureMismatchData {
+            SelectionError::SignatureMismatch(box SignatureMismatchData {
                 found_trait_ref,
                 expected_trait_ref,
                 terr: _,
@@ -690,7 +692,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 def_id,
             ),
 
-            TraitDynIncompatible(did) => {
+            SelectionError::TraitDynIncompatible(did) => {
                 let violations = self.tcx.dyn_compatibility_violations(did);
                 report_dyn_incompatibility(self.tcx, span, None, did, violations)
             }
@@ -710,12 +712,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             // Already reported in the query.
             SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(guar)) |
             // Already reported.
-            Overflow(OverflowError::Error(guar)) => {
+            SelectionError::Overflow(OverflowError::Error(guar)) => {
                 self.set_tainted_by_errors(guar);
                 return guar
             },
 
-            Overflow(_) => {
+            SelectionError::Overflow(_) => {
                 bug!("overflow should be handled before the `report_selection_error` path");
             }
 
@@ -775,7 +777,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         span: Span,
     ) -> Diag<'a> {
-        // FIXME(const_trait_impl): We should recompute the predicate with `~const`
+        // FIXME(const_trait_impl): We should recompute the predicate with `[const]`
         // if it's `const`, and if it holds, explain that this bound only
         // *conditionally* holds. If that fails, we should also do selection
         // to drill this down to an impl or built-in source, so we can
@@ -1186,7 +1188,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         ty: Ty<'tcx>,
         obligation: &PredicateObligation<'tcx>,
     ) -> Diag<'a> {
-        let span = obligation.cause.span;
+        let param = obligation.cause.body_id;
+        let hir::GenericParamKind::Const { ty: &hir::Ty { span, .. }, .. } =
+            self.tcx.hir_node_by_def_id(param).expect_generic_param().kind
+        else {
+            bug!()
+        };
 
         let mut diag = match ty.kind() {
             ty::Float(_) => {
@@ -1850,7 +1857,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let trait_def_id = trait_pred.def_id();
         let trait_name = self.tcx.item_name(trait_def_id);
         let crate_name = self.tcx.crate_name(trait_def_id.krate);
-        if let Some(other_trait_def_id) = self.tcx.all_traits().find(|def_id| {
+        if let Some(other_trait_def_id) = self.tcx.all_traits_including_private().find(|def_id| {
             trait_name == self.tcx.item_name(trait_def_id)
                 && trait_def_id.krate != def_id.krate
                 && crate_name == self.tcx.crate_name(def_id.krate)
@@ -1928,7 +1935,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     StringPart::highlighted("multiple different versions".to_string()),
                     StringPart::normal(" of crate `".to_string()),
                     StringPart::highlighted(format!("{crate_name}")),
-                    StringPart::normal("` in the dependency graph\n".to_string()),
+                    StringPart::normal("` in the dependency graph".to_string()),
                 ],
             );
             if points_at_type {
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 89dab90dc68..2344bc79f21 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
@@ -11,7 +11,9 @@ use rustc_macros::LintDiagnostic;
 use rustc_middle::bug;
 use rustc_middle::ty::print::PrintTraitRefExt;
 use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt};
-use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
+use rustc_session::lint::builtin::{
+    MALFORMED_DIAGNOSTIC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
+};
 use rustc_span::{Span, Symbol, sym};
 use tracing::{debug, info};
 
@@ -334,7 +336,7 @@ pub struct OnUnimplementedNote {
     pub append_const_msg: Option<AppendConstMessage>,
 }
 
-/// Append a message for `~const Trait` errors.
+/// Append a message for `[const] Trait` errors.
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
 pub enum AppendConstMessage {
     #[default]
@@ -382,7 +384,7 @@ impl IgnoredDiagnosticOption {
         if let (Some(new_item), Some(old_item)) = (new, old) {
             if let Some(item_def_id) = item_def_id.as_local() {
                 tcx.emit_node_span_lint(
-                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                    MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                     tcx.local_def_id_to_hir_id(item_def_id),
                     new_item,
                     IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name },
@@ -533,7 +535,7 @@ impl<'tcx> OnUnimplementedDirective {
             if is_diagnostic_namespace_variant {
                 if let Some(def_id) = item_def_id.as_local() {
                     tcx.emit_node_span_lint(
-                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                        MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                         tcx.local_def_id_to_hir_id(def_id),
                         vec![item.span()],
                         MalformedOnUnimplementedAttrLint::new(item.span()),
@@ -689,7 +691,7 @@ impl<'tcx> OnUnimplementedDirective {
 
                 if let Some(item_def_id) = item_def_id.as_local() {
                     tcx.emit_node_span_lint(
-                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                        MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                         tcx.local_def_id_to_hir_id(item_def_id),
                         report_span,
                         MalformedOnUnimplementedAttrLint::new(report_span),
@@ -702,7 +704,7 @@ impl<'tcx> OnUnimplementedDirective {
                 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,
+                            MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                             tcx.local_def_id_to_hir_id(item_def_id),
                             attr.span(),
                             MalformedOnUnimplementedAttrLint::new(attr.span()),
@@ -712,7 +714,7 @@ impl<'tcx> OnUnimplementedDirective {
                 _ => {
                     if let Some(item_def_id) = item_def_id.as_local() {
                         tcx.emit_node_span_lint(
-                            UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                            MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                             tcx.local_def_id_to_hir_id(item_def_id),
                             attr.span(),
                             MissingOptionsForOnUnimplementedAttr,
@@ -859,7 +861,7 @@ impl<'tcx> OnUnimplementedFormatString {
                 if self.is_diagnostic_namespace_variant {
                     if let Some(trait_def_id) = trait_def_id.as_local() {
                         tcx.emit_node_span_lint(
-                            UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                            MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
                             tcx.local_def_id_to_hir_id(trait_def_id),
                             self.span,
                             WrappedParserError { description: e.description, label: e.label },
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs
index 3e8b906fa93..1954f8a1f63 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs
@@ -7,7 +7,7 @@ use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
 use rustc_parse_format::{
     Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position,
 };
-use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
+use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_FORMAT_LITERALS;
 use rustc_span::def_id::DefId;
 use rustc_span::{InnerSpan, Span, Symbol, kw, sym};
 
@@ -69,7 +69,7 @@ impl FormatWarning {
                 let this = tcx.item_ident(item_def_id);
                 if let Some(item_def_id) = item_def_id.as_local() {
                     tcx.emit_node_span_lint(
-                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                        MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
                         tcx.local_def_id_to_hir_id(item_def_id),
                         span,
                         UnknownFormatParameterForOnUnimplementedAttr {
@@ -82,7 +82,7 @@ impl FormatWarning {
             FormatWarning::PositionalArgument { span, .. } => {
                 if let Some(item_def_id) = item_def_id.as_local() {
                     tcx.emit_node_span_lint(
-                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                        MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
                         tcx.local_def_id_to_hir_id(item_def_id),
                         span,
                         DisallowedPositionalArgument,
@@ -92,7 +92,7 @@ impl FormatWarning {
             FormatWarning::InvalidSpecifier { span, .. } => {
                 if let Some(item_def_id) = item_def_id.as_local() {
                     tcx.emit_node_span_lint(
-                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                        MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
                         tcx.local_def_id_to_hir_id(item_def_id),
                         span,
                         InvalidFormatSpecifier,
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 6d07ae021ae..bd1d29826e6 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -1187,6 +1187,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         has_custom_message: bool,
     ) -> bool {
         let span = obligation.cause.span;
+        let param_env = obligation.param_env;
+
+        let mk_result = |trait_pred_and_new_ty| {
+            let obligation =
+                self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
+            self.predicate_must_hold_modulo_regions(&obligation)
+        };
 
         let code = match obligation.cause.code() {
             ObligationCauseCode::FunctionArg { parent_code, .. } => parent_code,
@@ -1195,6 +1202,76 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             c @ ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, _)
                 if self.tcx.hir_span(*hir_id).lo() == span.lo() =>
             {
+                // `hir_id` corresponds to the HIR node that introduced a `where`-clause obligation.
+                // If that obligation comes from a type in an associated method call, we need
+                // special handling here.
+                if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(*hir_id)
+                    && let hir::ExprKind::Call(base, _) = expr.kind
+                    && let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, segment)) = base.kind
+                    && let hir::Node::Expr(outer) = self.tcx.parent_hir_node(expr.hir_id)
+                    && let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mtbl, _) = outer.kind
+                    && ty.span == span
+                {
+                    // We've encountered something like `&str::from("")`, where the intended code
+                    // was likely `<&str>::from("")`. The former is interpreted as "call method
+                    // `from` on `str` and borrow the result", while the latter means "call method
+                    // `from` on `&str`".
+
+                    let trait_pred_and_imm_ref = poly_trait_pred.map_bound(|p| {
+                        (p, Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty()))
+                    });
+                    let trait_pred_and_mut_ref = poly_trait_pred.map_bound(|p| {
+                        (p, Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty()))
+                    });
+
+                    let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);
+                    let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
+                    let sugg_msg = |pre: &str| {
+                        format!(
+                            "you likely meant to call the associated function `{FN}` for type \
+                             `&{pre}{TY}`, but the code as written calls associated function `{FN}` on \
+                             type `{TY}`",
+                            FN = segment.ident,
+                            TY = poly_trait_pred.self_ty(),
+                        )
+                    };
+                    match (imm_ref_self_ty_satisfies_pred, mut_ref_self_ty_satisfies_pred, mtbl) {
+                        (true, _, hir::Mutability::Not) | (_, true, hir::Mutability::Mut) => {
+                            err.multipart_suggestion_verbose(
+                                sugg_msg(mtbl.prefix_str()),
+                                vec![
+                                    (outer.span.shrink_to_lo(), "<".to_string()),
+                                    (span.shrink_to_hi(), ">".to_string()),
+                                ],
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                        (true, _, hir::Mutability::Mut) => {
+                            // There's an associated function found on the immutable borrow of the
+                            err.multipart_suggestion_verbose(
+                                sugg_msg("mut "),
+                                vec![
+                                    (outer.span.shrink_to_lo().until(span), "<&".to_string()),
+                                    (span.shrink_to_hi(), ">".to_string()),
+                                ],
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                        (_, true, hir::Mutability::Not) => {
+                            err.multipart_suggestion_verbose(
+                                sugg_msg(""),
+                                vec![
+                                    (outer.span.shrink_to_lo().until(span), "<&mut ".to_string()),
+                                    (span.shrink_to_hi(), ">".to_string()),
+                                ],
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                        _ => {}
+                    }
+                    // If we didn't return early here, we would instead suggest `&&str::from("")`.
+                    return false;
+                }
                 c
             }
             c if matches!(
@@ -1220,8 +1297,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             never_suggest_borrow.push(def_id);
         }
 
-        let param_env = obligation.param_env;
-
         // Try to apply the original trait bound by borrowing.
         let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
                                  blacklist: &[DefId]|
@@ -1243,15 +1318,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 )
             });
 
-            let mk_result = |trait_pred_and_new_ty| {
-                let obligation =
-                    self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
-                self.predicate_must_hold_modulo_regions(&obligation)
-            };
             let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);
             let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
 
-            let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) =
+            let (ref_inner_ty_satisfies_pred, ref_inner_ty_is_mut) =
                 if let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code()
                     && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind()
                 {
@@ -1263,117 +1333,139 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     (false, false)
                 };
 
-            if imm_ref_self_ty_satisfies_pred
-                || mut_ref_self_ty_satisfies_pred
-                || ref_inner_ty_satisfies_pred
-            {
-                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                    // We don't want a borrowing suggestion on the fields in structs,
-                    // ```
-                    // struct Foo {
-                    //  the_foos: Vec<Foo>
-                    // }
-                    // ```
-                    if !matches!(
-                        span.ctxt().outer_expn_data().kind,
-                        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
-                    ) {
-                        return false;
-                    }
-                    if snippet.starts_with('&') {
-                        // This is already a literal borrow and the obligation is failing
-                        // somewhere else in the obligation chain. Do not suggest non-sense.
-                        return false;
-                    }
-                    // We have a very specific type of error, where just borrowing this argument
-                    // might solve the problem. In cases like this, the important part is the
-                    // original type obligation, not the last one that failed, which is arbitrary.
-                    // Because of this, we modify the error to refer to the original obligation and
-                    // return early in the caller.
-
-                    let msg = format!(
-                        "the trait bound `{}` is not satisfied",
-                        self.tcx.short_string(old_pred, err.long_ty_path()),
-                    );
-                    let self_ty_str =
-                        self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path());
-                    if has_custom_message {
-                        err.note(msg);
-                    } else {
-                        err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)];
-                    }
-                    err.span_label(
-                        span,
-                        format!(
-                            "the trait `{}` is not implemented for `{self_ty_str}`",
-                            old_pred.print_modifiers_and_trait_path()
-                        ),
-                    );
+            let is_immut = imm_ref_self_ty_satisfies_pred
+                || (ref_inner_ty_satisfies_pred && !ref_inner_ty_is_mut);
+            let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_is_mut;
+            if !is_immut && !is_mut {
+                return false;
+            }
+            let Ok(_snippet) = self.tcx.sess.source_map().span_to_snippet(span) else {
+                return false;
+            };
+            // We don't want a borrowing suggestion on the fields in structs
+            // ```
+            // #[derive(Clone)]
+            // struct Foo {
+            //     the_foos: Vec<Foo>
+            // }
+            // ```
+            if !matches!(
+                span.ctxt().outer_expn_data().kind,
+                ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
+            ) {
+                return false;
+            }
+            // We have a very specific type of error, where just borrowing this argument
+            // might solve the problem. In cases like this, the important part is the
+            // original type obligation, not the last one that failed, which is arbitrary.
+            // Because of this, we modify the error to refer to the original obligation and
+            // return early in the caller.
 
-                    if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred {
-                        err.span_suggestions(
-                            span.shrink_to_lo(),
-                            "consider borrowing here",
-                            ["&".to_string(), "&mut ".to_string()],
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
-                        let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
-                        let sugg_msg = format!(
-                            "consider{} borrowing here",
-                            if is_mut { " mutably" } else { "" }
-                        );
+            let mut label = || {
+                let msg = format!(
+                    "the trait bound `{}` is not satisfied",
+                    self.tcx.short_string(old_pred, err.long_ty_path()),
+                );
+                let self_ty_str =
+                    self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path());
+                if has_custom_message {
+                    err.note(msg);
+                } else {
+                    err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)];
+                }
+                err.span_label(
+                    span,
+                    format!(
+                        "the trait `{}` is not implemented for `{self_ty_str}`",
+                        old_pred.print_modifiers_and_trait_path()
+                    ),
+                );
+            };
 
-                        // Issue #109436, we need to add parentheses properly for method calls
-                        // for example, `foo.into()` should be `(&foo).into()`
-                        if let Some(_) =
-                            self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50))
-                        {
-                            err.multipart_suggestion_verbose(
-                                sugg_msg,
-                                vec![
-                                    (span.shrink_to_lo(), format!("({sugg_prefix}")),
-                                    (span.shrink_to_hi(), ")".to_string()),
-                                ],
-                                Applicability::MaybeIncorrect,
-                            );
-                            return true;
-                        }
+            let mut sugg_prefixes = vec![];
+            if is_immut {
+                sugg_prefixes.push("&");
+            }
+            if is_mut {
+                sugg_prefixes.push("&mut ");
+            }
+            let sugg_msg = format!(
+                "consider{} borrowing here",
+                if is_mut && !is_immut { " mutably" } else { "" },
+            );
 
-                        // 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)
-                        else {
-                            return false;
-                        };
-                        let mut expr_finder = FindExprBySpan::new(span, self.tcx);
-                        expr_finder.visit_expr(body.value);
-                        let Some(expr) = expr_finder.result else {
-                            return false;
-                        };
-                        let needs_parens = expr_needs_parens(expr);
+            // 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) else {
+                return false;
+            };
+            let mut expr_finder = FindExprBySpan::new(span, self.tcx);
+            expr_finder.visit_expr(body.value);
 
-                        let span = if needs_parens { span } else { span.shrink_to_lo() };
-                        let suggestions = if !needs_parens {
-                            vec![(span.shrink_to_lo(), sugg_prefix)]
-                        } else {
+            if let Some(ty) = expr_finder.ty_result {
+                if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(ty.hir_id)
+                    && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, _)) = expr.kind
+                    && ty.span == span
+                {
+                    // We've encountered something like `str::from("")`, where the intended code
+                    // was likely `<&str>::from("")`. #143393.
+                    label();
+                    err.multipart_suggestions(
+                        sugg_msg,
+                        sugg_prefixes.into_iter().map(|sugg_prefix| {
                             vec![
-                                (span.shrink_to_lo(), format!("{sugg_prefix}(")),
-                                (span.shrink_to_hi(), ")".to_string()),
+                                (span.shrink_to_lo(), format!("<{sugg_prefix}")),
+                                (span.shrink_to_hi(), ">".to_string()),
                             ]
-                        };
-                        err.multipart_suggestion_verbose(
-                            sugg_msg,
-                            suggestions,
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
+                        }),
+                        Applicability::MaybeIncorrect,
+                    );
                     return true;
                 }
+                return false;
             }
-            return false;
+            let Some(expr) = expr_finder.result else {
+                return false;
+            };
+            if let hir::ExprKind::AddrOf(_, _, _) = expr.kind {
+                return false;
+            }
+            let needs_parens_post = expr_needs_parens(expr);
+            let needs_parens_pre = match self.tcx.parent_hir_node(expr.hir_id) {
+                Node::Expr(e)
+                    if let hir::ExprKind::MethodCall(_, base, _, _) = e.kind
+                        && base.hir_id == expr.hir_id =>
+                {
+                    true
+                }
+                _ => false,
+            };
+
+            label();
+            let suggestions = sugg_prefixes.into_iter().map(|sugg_prefix| {
+                match (needs_parens_pre, needs_parens_post) {
+                    (false, false) => vec![(span.shrink_to_lo(), sugg_prefix.to_string())],
+                    // We have something like `foo.bar()`, where we want to bororw foo, so we need
+                    // to suggest `(&mut foo).bar()`.
+                    (false, true) => vec![
+                        (span.shrink_to_lo(), format!("{sugg_prefix}(")),
+                        (span.shrink_to_hi(), ")".to_string()),
+                    ],
+                    // Issue #109436, we need to add parentheses properly for method calls
+                    // for example, `foo.into()` should be `(&foo).into()`
+                    (true, false) => vec![
+                        (span.shrink_to_lo(), format!("({sugg_prefix}")),
+                        (span.shrink_to_hi(), ")".to_string()),
+                    ],
+                    (true, true) => vec![
+                        (span.shrink_to_lo(), format!("({sugg_prefix}(")),
+                        (span.shrink_to_hi(), "))".to_string()),
+                    ],
+                }
+            });
+            err.multipart_suggestions(sugg_msg, suggestions, Applicability::MaybeIncorrect);
+            return true;
         };
 
         if let ObligationCauseCode::ImplDerived(cause) = &*code {
@@ -1511,12 +1603,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         'outer: loop {
             while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind {
                 count += 1;
-                let span = if expr.span.eq_ctxt(borrowed.span) {
-                    expr.span.until(borrowed.span)
-                } else {
-                    expr.span.with_hi(expr.span.lo() + BytePos(1))
-                };
+                let span =
+                    if let Some(borrowed_span) = borrowed.span.find_ancestor_inside(expr.span) {
+                        expr.span.until(borrowed_span)
+                    } else {
+                        break 'outer;
+                    };
 
+                // Double check that the span we extracted actually corresponds to a borrow,
+                // rather than some macro garbage.
                 match self.tcx.sess.source_map().span_to_snippet(span) {
                     Ok(snippet) if snippet.starts_with("&") => {}
                     _ => break 'outer,
@@ -2721,6 +2816,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             ObligationCauseCode::TupleElem => {
                 err.note("only the last element of a tuple may have a dynamically sized type");
             }
+            ObligationCauseCode::DynCompatible(span) => {
+                err.multipart_suggestion(
+                    "you might have meant to use `Self` to refer to the implementing type",
+                    vec![(span, "Self".into())],
+                    Applicability::MachineApplicable,
+                );
+            }
             ObligationCauseCode::WhereClause(item_def_id, span)
             | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)
             | ObligationCauseCode::HostEffectInExpr(item_def_id, span, ..)
@@ -2872,13 +2974,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         _ => (),
                     }
                 }
-                let descr = format!("required by {a} bound in `{item_name}`");
-                if span.is_visible(sm) {
-                    let msg = format!("required by {this} in `{short_item_name}`");
-                    multispan.push_span_label(span, msg);
-                    err.span_note(multispan, descr);
+
+                // If this is from a format string literal desugaring,
+                // we've already said "required by this formatting parameter"
+                let is_in_fmt_lit = if let Some(s) = err.span.primary_span() {
+                    matches!(s.desugaring_kind(), Some(DesugaringKind::FormatLiteral { .. }))
                 } else {
-                    err.span_note(tcx.def_span(item_def_id), descr);
+                    false
+                };
+                if !is_in_fmt_lit {
+                    let descr = format!("required by {a} bound in `{item_name}`");
+                    if span.is_visible(sm) {
+                        let msg = format!("required by {this} in `{short_item_name}`");
+                        multispan.push_span_label(span, msg);
+                        err.span_note(multispan, descr);
+                    } else {
+                        err.span_note(tcx.def_span(item_def_id), descr);
+                    }
                 }
                 if let Some(note) = note {
                     err.note(note);
@@ -3607,6 +3719,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 );
                 suggest_remove_deref(err, &expr);
             }
+            ObligationCauseCode::UnsizedNonPlaceExpr(span) => {
+                err.span_note(
+                    span,
+                    "unsized values must be place expressions and cannot be put in temporaries",
+                );
+            }
         }
     }
 
@@ -3973,7 +4091,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             ) = expr.kind
             {
                 if Some(*span) != err.span.primary_span() {
-                    err.span_label(*span, "required by a bound introduced by this call");
+                    let msg = if span.is_desugaring(DesugaringKind::FormatLiteral { source: true })
+                    {
+                        "required by this formatting parameter"
+                    } else if span.is_desugaring(DesugaringKind::FormatLiteral { source: false }) {
+                        "required by a formatting parameter in this expression"
+                    } else {
+                        "required by a bound introduced by this call"
+                    };
+                    err.span_label(*span, msg);
                 }
             }
 
@@ -4407,7 +4533,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         candidate_impls: &[ImplCandidate<'tcx>],
         span: Span,
     ) {
-        // We can only suggest the slice coersion for function and binary operation arguments,
+        // We can only suggest the slice coercion for function and binary operation arguments,
         // since the suggestion would make no sense in turbofish or call
         let (ObligationCauseCode::BinOp { .. } | ObligationCauseCode::FunctionArg { .. }) =
             obligation.cause.code()
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 7bf49056e29..90cdf75265d 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -643,7 +643,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
                 // Do not suggest constraining the `&self` param, but rather the return type.
                 // If that is wrong (because it is not sufficient), a follow up error will tell the
                 // user to fix it. This way we lower the chances of *over* constraining, but still
-                // get the cake of "correctly" contrained in two steps.
+                // get the cake of "correctly" constrained in two steps.
                 visitor.visit_ty_unambig(self.ty_sup);
             }
             visitor.visit_ty_unambig(self.ty_sub);
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 84e7686fdd3..3471036256d 100644
--- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
@@ -32,21 +32,22 @@ impl<'a> DescriptionCtx<'a> {
                 } else {
                     tcx.def_span(scope)
                 };
-                if br.has_name() {
+                if br.is_named() {
                     (Some(span), "as_defined", br.name.to_string())
                 } else {
                     (Some(span), "as_defined_anon", String::new())
                 }
             }
             ty::ReLateParam(ref fr) => {
-                if !fr.kind.is_named()
+                if !fr.kind.is_named(tcx)
                     && let Some((ty, _)) = find_anon_type(tcx, generic_param_scope, region)
                 {
                     (Some(ty.span), "defined_here", String::new())
                 } else {
                     let scope = fr.scope.expect_local();
                     match fr.kind {
-                        ty::LateParamRegionKind::Named(_, name) => {
+                        ty::LateParamRegionKind::Named(def_id) => {
+                            let name = tcx.item_name(def_id);
                             let span = if let Some(param) = tcx
                                 .hir_get_generics(scope)
                                 .and_then(|generics| generics.get_named(name))
@@ -163,12 +164,14 @@ impl RegionExplanation<'_> {
 
 impl Subdiagnostic for RegionExplanation<'_> {
     fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
+        diag.store_args();
         diag.arg("pref_kind", self.prefix);
         diag.arg("suff_kind", self.suffix);
         diag.arg("desc_kind", self.desc.kind);
         diag.arg("desc_arg", self.desc.arg);
 
         let msg = diag.eagerly_translate(fluent::trait_selection_region_explanation);
+        diag.restore_args();
         if let Some(span) = self.desc.span {
             diag.span_note(span, msg);
         } else {
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index b247c2c2968..1a24254d57f 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -143,6 +143,16 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
                     None
                 }
             }
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+                let arg = self.shallow_resolve_term(arg);
+                if arg.is_trivially_wf(self.tcx) {
+                    Some(Certainty::Yes)
+                } else if arg.is_infer() {
+                    Some(Certainty::AMBIGUOUS)
+                } else {
+                    None
+                }
+            }
             _ => None,
         }
     }
@@ -154,7 +164,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
     ) -> ty::GenericArg<'tcx> {
         match arg.kind() {
             ty::GenericArgKind::Lifetime(_) => {
-                self.next_region_var(RegionVariableOrigin::MiscVariable(span)).into()
+                self.next_region_var(RegionVariableOrigin::Misc(span)).into()
             }
             ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(),
             ty::GenericArgKind::Const(_) => self.next_const_var(span).into(),
@@ -203,13 +213,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         // inside of a `probe` whenever we have multiple choices inside of the solver.
         let region_obligations = self.0.inner.borrow().region_obligations().to_owned();
         let region_constraints = self.0.with_region_constraints(|region_constraints| {
-            make_query_region_constraints(
-                self.tcx,
-                region_obligations
-                    .iter()
-                    .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())),
-                region_constraints,
-            )
+            make_query_region_constraints(self.tcx, region_obligations, region_constraints)
         });
 
         let mut seen = FxHashSet::default();
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index ed99c678a4d..d56042a5ca2 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -14,7 +14,7 @@ use rustc_middle::ty::{
 };
 use rustc_next_trait_solver::delegate::SolverDelegate as _;
 use rustc_next_trait_solver::solve::{
-    GenerateProofTree, GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt as _,
+    GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt as _,
 };
 use rustc_span::Span;
 use thin_vec::ThinVec;
@@ -106,14 +106,11 @@ impl<'tcx> ObligationStorage<'tcx> {
             self.overflowed.extend(
                 ExtractIf::new(&mut self.pending, |(o, stalled_on)| {
                     let goal = o.as_goal();
-                    let result = <&SolverDelegate<'tcx>>::from(infcx)
-                        .evaluate_root_goal(
-                            goal,
-                            GenerateProofTree::No,
-                            o.cause.span,
-                            stalled_on.take(),
-                        )
-                        .0;
+                    let result = <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal(
+                        goal,
+                        o.cause.span,
+                        stalled_on.take(),
+                    );
                     matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. }))
                 })
                 .map(|(o, _)| o),
@@ -207,14 +204,7 @@ where
                     continue;
                 }
 
-                let result = delegate
-                    .evaluate_root_goal(
-                        goal,
-                        GenerateProofTree::No,
-                        obligation.cause.span,
-                        stalled_on,
-                    )
-                    .0;
+                let result = delegate.evaluate_root_goal(goal, obligation.cause.span, stalled_on);
                 self.inspect_evaluated_obligation(infcx, &obligation, &result);
                 let GoalEvaluation { certainty, has_changed, stalled_on } = match result {
                     Ok(result) => result,
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 36a8ae675c0..e31d1052d16 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
@@ -11,9 +11,7 @@ use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
-use rustc_next_trait_solver::solve::{
-    GenerateProofTree, GoalEvaluation, SolverDelegateEvalExt as _,
-};
+use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt as _};
 use tracing::{instrument, trace};
 
 use crate::solve::delegate::SolverDelegate;
@@ -39,7 +37,9 @@ pub(super) fn fulfillment_error_for_no_solution<'tcx>(
                 ty::ConstKind::Unevaluated(uv) => {
                     infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
                 }
-                ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(obligation.param_env),
+                ty::ConstKind::Param(param_ct) => {
+                    param_ct.find_const_ty_from_env(obligation.param_env)
+                }
                 ty::ConstKind::Value(cv) => cv.ty,
                 kind => span_bug!(
                     obligation.cause.span,
@@ -90,15 +90,11 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>(
     root_obligation: PredicateObligation<'tcx>,
 ) -> FulfillmentError<'tcx> {
     let (code, refine_obligation) = infcx.probe(|_| {
-        match <&SolverDelegate<'tcx>>::from(infcx)
-            .evaluate_root_goal(
-                root_obligation.as_goal(),
-                GenerateProofTree::No,
-                root_obligation.cause.span,
-                None,
-            )
-            .0
-        {
+        match <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal(
+            root_obligation.as_goal(),
+            root_obligation.cause.span,
+            None,
+        ) {
             Ok(GoalEvaluation { certainty: Certainty::Maybe(MaybeCause::Ambiguity), .. }) => {
                 (FulfillmentErrorCode::Ambiguity { overflow: None }, true)
             }
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index b0c8fa1f217..308486811e6 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -20,7 +20,7 @@ use rustc_middle::ty::{TyCtxt, VisitorResult, try_visit};
 use rustc_middle::{bug, ty};
 use rustc_next_trait_solver::resolve::eager_resolve_vars;
 use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state};
-use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _};
+use rustc_next_trait_solver::solve::{MaybeCause, SolverDelegateEvalExt as _};
 use rustc_span::Span;
 use tracing::instrument;
 
@@ -37,7 +37,7 @@ pub struct InspectGoal<'a, 'tcx> {
     orig_values: Vec<ty::GenericArg<'tcx>>,
     goal: Goal<'tcx, ty::Predicate<'tcx>>,
     result: Result<Certainty, NoSolution>,
-    evaluation_kind: inspect::CanonicalGoalEvaluationKind<TyCtxt<'tcx>>,
+    evaluation_kind: inspect::GoalEvaluationKind<TyCtxt<'tcx>>,
     normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>,
     source: GoalSource,
 }
@@ -248,9 +248,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
                     // considering the constrained RHS, and pass the resulting certainty to
                     // `InspectGoal::new` so that the goal has the right result (and maintains
                     // the impression that we don't do this normalizes-to infer hack at all).
-                    let (nested, proof_tree) =
-                        infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None);
-                    let proof_tree = proof_tree.unwrap();
+                    let (nested, proof_tree) = infcx.evaluate_root_goal_for_proof_tree(goal, span);
                     let nested_goals_result = nested.and_then(|(nested, _)| {
                         normalizes_to_term_hack.constrain_and(
                             infcx,
@@ -284,9 +282,8 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
                 // into another candidate who ends up with different inference
                 // constraints, we get an ICE if we already applied the constraints
                 // from the chosen candidate.
-                let proof_tree = infcx
-                    .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes, span, None).1)
-                    .unwrap();
+                let proof_tree =
+                    infcx.probe(|_| infcx.evaluate_root_goal_for_proof_tree(goal, span).1);
                 InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
             }
         }
@@ -396,8 +393,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
         let mut candidates = vec![];
         let last_eval_step = match &self.evaluation_kind {
             // An annoying edge case in case the recursion limit is 0.
-            inspect::CanonicalGoalEvaluationKind::Overflow => return vec![],
-            inspect::CanonicalGoalEvaluationKind::Evaluation { final_revision } => final_revision,
+            inspect::GoalEvaluationKind::Overflow => return vec![],
+            inspect::GoalEvaluationKind::Evaluation { final_revision } => final_revision,
         };
 
         let mut nested_goals = vec![];
@@ -429,10 +426,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
     ) -> Self {
         let infcx = <&SolverDelegate<'tcx>>::from(infcx);
 
-        let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root;
+        let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, kind, result } = root;
         // If there's a normalizes-to goal, AND the evaluation result with the result of
         // constraining the normalizes-to RHS and computing the nested goals.
-        let result = evaluation.result.and_then(|ok| {
+        let result = result.and_then(|ok| {
             let nested_goals_certainty =
                 term_hack_and_nested_certainty.map_or(Ok(Certainty::Yes), |(_, c)| c)?;
             Ok(ok.value.certainty.and(nested_goals_certainty))
@@ -444,7 +441,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
             orig_values,
             goal: eager_resolve_vars(infcx, uncanonicalized_goal),
             result,
-            evaluation_kind: evaluation.kind,
+            evaluation_kind: kind,
             normalizes_to_term_hack: term_hack_and_nested_certainty.map(|(n, _)| n),
             source,
         }
@@ -488,13 +485,8 @@ impl<'tcx> InferCtxt<'tcx> {
         depth: usize,
         visitor: &mut V,
     ) -> V::Result {
-        let (_, proof_tree) = <&SolverDelegate<'tcx>>::from(self).evaluate_root_goal(
-            goal,
-            GenerateProofTree::Yes,
-            visitor.span(),
-            None,
-        );
-        let proof_tree = proof_tree.unwrap();
+        let (_, proof_tree) = <&SolverDelegate<'tcx>>::from(self)
+            .evaluate_root_goal_for_proof_tree(goal, visitor.span());
         visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc))
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 3ae908ec16b..759db1d18c0 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -800,6 +800,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 // FIXME(generic_const_exprs): you can absolutely add this as a where clauses
                 | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
                 | ty::PredicateKind::Coerce(..)
+                | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
                 | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {}
                 ty::PredicateKind::Ambiguous => return false,
             };
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 81893cdcc7e..ce5a4edeaaa 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -356,29 +356,38 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
             return IntersectionHasImpossibleObligations::Yes;
         }
 
-        let ocx = ObligationCtxt::new_with_diagnostics(infcx);
+        let ocx = ObligationCtxt::new(infcx);
         ocx.register_obligations(obligations.iter().cloned());
+        let hard_errors = ocx.select_where_possible();
+        if !hard_errors.is_empty() {
+            assert!(
+                hard_errors.iter().all(|e| e.is_true_error()),
+                "should not have detected ambiguity during first pass"
+            );
+            return IntersectionHasImpossibleObligations::Yes;
+        }
+
+        // Make a new `ObligationCtxt` and re-prove the ambiguities with a richer
+        // `FulfillmentError`. This is so that we can detect overflowing obligations
+        // without needing to run the `BestObligation` visitor on true errors.
+        let ambiguities = ocx.into_pending_obligations();
+        let ocx = ObligationCtxt::new_with_diagnostics(infcx);
+        ocx.register_obligations(ambiguities);
         let errors_and_ambiguities = ocx.select_all_or_error();
         // We only care about the obligations that are *definitely* true errors.
         // Ambiguities do not prove the disjointness of two impls.
         let (errors, ambiguities): (Vec<_>, Vec<_>) =
             errors_and_ambiguities.into_iter().partition(|error| error.is_true_error());
-
-        if errors.is_empty() {
-            IntersectionHasImpossibleObligations::No {
-                overflowing_predicates: ambiguities
-                    .into_iter()
-                    .filter(|error| {
-                        matches!(
-                            error.code,
-                            FulfillmentErrorCode::Ambiguity { overflow: Some(true) }
-                        )
-                    })
-                    .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
-                    .collect(),
-            }
-        } else {
-            IntersectionHasImpossibleObligations::Yes
+        assert!(errors.is_empty(), "should not have ambiguities during second pass");
+
+        IntersectionHasImpossibleObligations::No {
+            overflowing_predicates: ambiguities
+                .into_iter()
+                .filter(|error| {
+                    matches!(error.code, FulfillmentErrorCode::Ambiguity { overflow: Some(true) })
+                })
+                .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
+                .collect(),
         }
     } else {
         for obligation in obligations {
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index ee30956295a..ea1eed95723 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -31,7 +31,7 @@ use crate::traits::{
 ///
 /// Currently that is `Self` in supertraits. This is needed
 /// because `dyn_compatibility_violations` can't be used during
-/// type collection.
+/// type collection, as type collection is needed for `dyn_compatibility_violations` itself.
 #[instrument(level = "debug", skip(tcx), ret)]
 pub fn hir_ty_lowering_dyn_compatibility_violations(
     tcx: TyCtxt<'_>,
@@ -238,6 +238,7 @@ fn predicate_references_self<'tcx>(
         // FIXME(generic_const_exprs): this can mention `Self`
         | ty::ClauseKind::ConstEvaluatable(..)
         | ty::ClauseKind::HostEffect(..)
+        | ty::ClauseKind::UnstableFeature(_)
          => None,
     }
 }
@@ -278,6 +279,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         | ty::ClauseKind::ConstArgHasType(_, _)
         | ty::ClauseKind::WellFormed(_)
         | ty::ClauseKind::ConstEvaluatable(_)
+        | ty::ClauseKind::UnstableFeature(_)
         | ty::ClauseKind::HostEffect(..) => false,
     })
 }
@@ -593,7 +595,7 @@ fn receiver_is_dispatchable<'tcx>(
         // will cause ambiguity that the user can't really avoid.
         //
         // We leave out certain complexities of the param-env query here. Specifically, we:
-        // 1. Do not add `~const` bounds since there are no `dyn const Trait`s.
+        // 1. Do not add `[const]` bounds since there are no `dyn const Trait`s.
         // 2. Do not add RPITIT self projection bounds for defaulted methods, since we
         //    are not constructing a param-env for "inside" of the body of the defaulted
         //    method, so we don't really care about projecting to a specific RPIT type,
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
index e77d9e32cb9..d694a092853 100644
--- a/compiler/rustc_trait_selection/src/traits/effects.rs
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -1,7 +1,8 @@
 use rustc_hir::{self as hir, LangItem};
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
 use rustc_infer::traits::{
-    ImplDerivedHostCause, ImplSource, Obligation, ObligationCauseCode, PredicateObligation,
+    ImplDerivedHostCause, ImplSource, Obligation, ObligationCause, ObligationCauseCode,
+    PredicateObligation,
 };
 use rustc_middle::span_bug;
 use rustc_middle::traits::query::NoSolution;
@@ -44,6 +45,12 @@ pub fn evaluate_host_effect_obligation<'tcx>(
         Err(EvaluationFailure::NoSolution) => {}
     }
 
+    match evaluate_host_effect_from_conditionally_const_item_bounds(selcx, obligation) {
+        Ok(result) => return Ok(result),
+        Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
+        Err(EvaluationFailure::NoSolution) => {}
+    }
+
     match evaluate_host_effect_from_item_bounds(selcx, obligation) {
         Ok(result) => return Ok(result),
         Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
@@ -56,7 +63,7 @@ pub fn evaluate_host_effect_obligation<'tcx>(
         Err(EvaluationFailure::NoSolution) => {}
     }
 
-    match evaluate_host_effect_from_selection_candiate(selcx, obligation) {
+    match evaluate_host_effect_from_selection_candidate(selcx, obligation) {
         Ok(result) => return Ok(result),
         Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
         Err(EvaluationFailure::NoSolution) => {}
@@ -153,7 +160,9 @@ fn evaluate_host_effect_from_bounds<'tcx>(
     }
 }
 
-fn evaluate_host_effect_from_item_bounds<'tcx>(
+/// Assembles constness bounds from `~const` item bounds on alias types, which only
+/// hold if the `~const` where bounds also hold and the parent trait is `~const`.
+fn evaluate_host_effect_from_conditionally_const_item_bounds<'tcx>(
     selcx: &mut SelectionContext<'_, 'tcx>,
     obligation: &HostEffectObligation<'tcx>,
 ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
@@ -232,12 +241,72 @@ fn evaluate_host_effect_from_item_bounds<'tcx>(
     }
 }
 
+/// Assembles constness bounds "normal" item bounds on aliases, which may include
+/// unconditionally `const` bounds that are *not* conditional and thus always hold.
+fn evaluate_host_effect_from_item_bounds<'tcx>(
+    selcx: &mut SelectionContext<'_, 'tcx>,
+    obligation: &HostEffectObligation<'tcx>,
+) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
+    let infcx = selcx.infcx;
+    let tcx = infcx.tcx;
+    let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
+    let mut candidate = None;
+
+    let mut consider_ty = obligation.predicate.self_ty();
+    while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() {
+        for clause in tcx.item_bounds(alias_ty.def_id).iter_instantiated(tcx, alias_ty.args) {
+            let bound_clause = clause.kind();
+            let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else {
+                continue;
+            };
+            let data = bound_clause.rebind(data);
+            if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
+                continue;
+            }
+
+            if !drcx.args_may_unify(
+                obligation.predicate.trait_ref.args,
+                data.skip_binder().trait_ref.args,
+            ) {
+                continue;
+            }
+
+            let is_match =
+                infcx.probe(|_| match_candidate(selcx, obligation, data, true, |_, _| {}).is_ok());
+
+            if is_match {
+                if candidate.is_some() {
+                    return Err(EvaluationFailure::Ambiguous);
+                } else {
+                    candidate = Some(data);
+                }
+            }
+        }
+
+        if kind != ty::Projection {
+            break;
+        }
+
+        consider_ty = alias_ty.self_ty();
+    }
+
+    if let Some(data) = candidate {
+        Ok(match_candidate(selcx, obligation, data, true, |_, _| {})
+            .expect("candidate matched before, so it should match again"))
+    } else {
+        Err(EvaluationFailure::NoSolution)
+    }
+}
+
 fn evaluate_host_effect_from_builtin_impls<'tcx>(
     selcx: &mut SelectionContext<'_, 'tcx>,
     obligation: &HostEffectObligation<'tcx>,
 ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
     match selcx.tcx().as_lang_item(obligation.predicate.def_id()) {
         Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation),
+        Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => {
+            evaluate_host_effect_for_fn_goal(selcx, obligation)
+        }
         _ => Err(EvaluationFailure::NoSolution),
     }
 }
@@ -252,20 +321,20 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>(
     let self_ty = obligation.predicate.self_ty();
 
     let const_conditions = match *self_ty.kind() {
-        // `ManuallyDrop` is trivially `~const Destruct` as we do not run any drop glue on it.
+        // `ManuallyDrop` is trivially `[const] Destruct` as we do not run any drop glue on it.
         ty::Adt(adt_def, _) if adt_def.is_manually_drop() => thin_vec![],
 
-        // An ADT is `~const Destruct` only if all of the fields are,
-        // *and* if there is a `Drop` impl, that `Drop` impl is also `~const`.
+        // An ADT is `[const] Destruct` only if all of the fields are,
+        // *and* if there is a `Drop` impl, that `Drop` impl is also `[const]`.
         ty::Adt(adt_def, args) => {
             let mut const_conditions: ThinVec<_> = adt_def
                 .all_fields()
                 .map(|field| ty::TraitRef::new(tcx, destruct_def_id, [field.ty(tcx, args)]))
                 .collect();
             match adt_def.destructor(tcx).map(|dtor| tcx.constness(dtor.did)) {
-                // `Drop` impl exists, but it's not const. Type cannot be `~const Destruct`.
+                // `Drop` impl exists, but it's not const. Type cannot be `[const] Destruct`.
                 Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution),
-                // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold.
+                // `Drop` impl exists, and it's const. Require `Ty: [const] Drop` to hold.
                 Some(hir::Constness::Const) => {
                     let drop_def_id = tcx.require_lang_item(LangItem::Drop, obligation.cause.span);
                     let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]);
@@ -285,7 +354,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>(
             tys.iter().map(|field_ty| ty::TraitRef::new(tcx, destruct_def_id, [field_ty])).collect()
         }
 
-        // Trivially implement `~const Destruct`
+        // Trivially implement `[const] Destruct`
         ty::Bool
         | ty::Char
         | ty::Int(..)
@@ -300,14 +369,14 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>(
         | ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_))
         | ty::Error(_) => thin_vec![],
 
-        // Coroutines and closures could implement `~const Drop`,
+        // Coroutines and closures could implement `[const] Drop`,
         // but they don't really need to right now.
         ty::Closure(_, _)
         | ty::CoroutineClosure(_, _)
         | ty::Coroutine(_, _)
         | ty::CoroutineWitness(_, _) => return Err(EvaluationFailure::NoSolution),
 
-        // FIXME(unsafe_binders): Unsafe binders could implement `~const Drop`
+        // FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop`
         // if their inner type implements it.
         ty::UnsafeBinder(_) => return Err(EvaluationFailure::NoSolution),
 
@@ -333,7 +402,52 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>(
         .collect())
 }
 
-fn evaluate_host_effect_from_selection_candiate<'tcx>(
+// NOTE: Keep this in sync with `extract_fn_def_from_const_callable` in the new solver.
+fn evaluate_host_effect_for_fn_goal<'tcx>(
+    selcx: &mut SelectionContext<'_, 'tcx>,
+    obligation: &HostEffectObligation<'tcx>,
+) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
+    let tcx = selcx.tcx();
+    let self_ty = obligation.predicate.self_ty();
+
+    let (def, args) = match *self_ty.kind() {
+        ty::FnDef(def, args) => (def, args),
+
+        // We may support function pointers at some point in the future
+        ty::FnPtr(..) => return Err(EvaluationFailure::NoSolution),
+
+        // Closures could implement `[const] Fn`,
+        // but they don't really need to right now.
+        ty::Closure(..) | ty::CoroutineClosure(_, _) => {
+            return Err(EvaluationFailure::NoSolution);
+        }
+
+        // Everything else needs explicit impls or cannot have an impl
+        _ => return Err(EvaluationFailure::NoSolution),
+    };
+
+    match tcx.constness(def) {
+        hir::Constness::Const => Ok(tcx
+            .const_conditions(def)
+            .instantiate(tcx, args)
+            .into_iter()
+            .map(|(c, span)| {
+                let code = ObligationCauseCode::WhereClause(def, span);
+                let cause =
+                    ObligationCause::new(obligation.cause.span, obligation.cause.body_id, code);
+                Obligation::new(
+                    tcx,
+                    cause,
+                    obligation.param_env,
+                    c.to_host_effect_clause(tcx, obligation.predicate.constness),
+                )
+            })
+            .collect()),
+        hir::Constness::NotConst => Err(EvaluationFailure::NoSolution),
+    }
+}
+
+fn evaluate_host_effect_from_selection_candidate<'tcx>(
     selcx: &mut SelectionContext<'_, 'tcx>,
     obligation: &HostEffectObligation<'tcx>,
 ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 951dfb879ae..2b5a41ef5a7 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -11,8 +11,10 @@ use rustc_infer::traits::{
 use rustc_middle::bug;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
-use thin_vec::ThinVec;
+use rustc_middle::ty::{
+    self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode, may_use_unstable_feature,
+};
+use thin_vec::{ThinVec, thin_vec};
 use tracing::{debug, debug_span, instrument};
 
 use super::effects::{self, HostEffectObligation};
@@ -20,7 +22,7 @@ use super::project::{self, ProjectAndUnifyResult};
 use super::select::SelectionContext;
 use super::{
     EvaluationResult, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
-    ScrubbedTraitError, Unimplemented, const_evaluatable, wf,
+    ScrubbedTraitError, const_evaluatable, wf,
 };
 use crate::error_reporting::InferCtxtErrorExt;
 use crate::infer::{InferCtxt, TyOrConstInferVar};
@@ -336,7 +338,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
         let infcx = self.selcx.infcx;
 
         if sizedness_fast_path(infcx.tcx, obligation.predicate) {
-            return ProcessResult::Changed(thin_vec::thin_vec![]);
+            return ProcessResult::Changed(thin_vec![]);
         }
 
         if obligation.predicate.has_aliases() {
@@ -404,6 +406,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 ty::PredicateKind::AliasRelate(..) => {
                     bug!("AliasRelate is only used by the new solver")
                 }
+                ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) => {
+                   unreachable!("unexpected higher ranked `UnstableFeature` goal")
+                }
             },
             Some(pred) => match pred {
                 ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
@@ -456,7 +461,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
 
                 ty::PredicateKind::DynCompatible(trait_def_id) => {
                     if !self.selcx.tcx().is_dyn_compatible(trait_def_id) {
-                        ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented))
+                        ProcessResult::Error(FulfillmentErrorCode::Select(
+                            SelectionError::Unimplemented,
+                        ))
                     } else {
                         ProcessResult::Changed(Default::default())
                     }
@@ -507,7 +514,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         }
                         ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
                         ty::ConstKind::Param(param_ct) => {
-                            param_ct.find_ty_from_env(obligation.param_env)
+                            param_ct.find_const_ty_from_env(obligation.param_env)
                         }
                     };
 
@@ -541,6 +548,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 }
 
                 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
+                    if term.is_trivially_wf(self.selcx.tcx()) {
+                        return ProcessResult::Changed(thin_vec![]);
+                    }
+
                     match wf::obligations(
                         self.selcx.infcx,
                         obligation.param_env,
@@ -761,6 +772,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         }
                     }
                 }
+                ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
+                    if may_use_unstable_feature(self.selcx.infcx, obligation.param_env, symbol) {
+                        ProcessResult::Changed(Default::default())
+                    } else {
+                        ProcessResult::Unchanged
+                    }
+                }
             },
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 999ef97683c..91c41544f78 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -36,8 +36,8 @@ use rustc_middle::ty::{
     self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
     TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Upcast,
 };
+use rustc_span::Span;
 use rustc_span::def_id::DefId;
-use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument};
 
 pub use self::coherence::{
@@ -481,7 +481,7 @@ pub enum EvaluateConstErr {
     /// some unevaluated constant with either generic parameters or inference variables in its
     /// generic arguments.
     HasGenericsOrInfers,
-    /// The type this constant evalauted to is not valid for use in const generics. This should
+    /// The type this constant evaluated to is not valid for use in const generics. This should
     /// always result in an error when checking the constant is correctly typed for the parameter
     /// it is an argument to, so a bug is delayed when encountering this.
     InvalidConstParamTy(ErrorGuaranteed),
@@ -644,7 +644,9 @@ pub fn try_evaluate_const<'tcx>(
             let erased_uv = tcx.erase_regions(uv);
 
             use rustc_middle::mir::interpret::ErrorHandled;
-            match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) {
+            // FIXME: `def_span` will point at the definition of this const; ideally, we'd point at
+            // where it gets used as a const generic.
+            match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, tcx.def_span(uv.def)) {
                 Ok(Ok(val)) => Ok(ty::Const::new_value(
                     tcx,
                     val,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 6dd80551980..28b5b7cf391 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -84,9 +84,6 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
     // was discarded -- this could be because of ambiguity, or because
     // a higher-priority candidate is already there.
     fn push_candidate(&mut self, candidate: ProjectionCandidate<'tcx>) -> bool {
-        use self::ProjectionCandidate::*;
-        use self::ProjectionCandidateSet::*;
-
         // This wacky variable is just used to try and
         // make code readable and avoid confusing paths.
         // It is assigned a "value" of `()` only on those
@@ -98,12 +95,12 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
         let convert_to_ambiguous;
 
         match self {
-            None => {
-                *self = Single(candidate);
+            ProjectionCandidateSet::None => {
+                *self = ProjectionCandidateSet::Single(candidate);
                 return true;
             }
 
-            Single(current) => {
+            ProjectionCandidateSet::Single(current) => {
                 // Duplicates can happen inside ParamEnv. In the case, we
                 // perform a lazy deduplication.
                 if current == &candidate {
@@ -118,16 +115,18 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
                 // clauses are the safer choice. See the comment on
                 // `select::SelectionCandidate` and #21974 for more details.
                 match (current, candidate) {
-                    (ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (),
-                    (ParamEnv(..), _) => return false,
-                    (_, ParamEnv(..)) => bug!(
+                    (ProjectionCandidate::ParamEnv(..), ProjectionCandidate::ParamEnv(..)) => {
+                        convert_to_ambiguous = ()
+                    }
+                    (ProjectionCandidate::ParamEnv(..), _) => return false,
+                    (_, ProjectionCandidate::ParamEnv(..)) => bug!(
                         "should never prefer non-param-env candidates over param-env candidates"
                     ),
                     (_, _) => convert_to_ambiguous = (),
                 }
             }
 
-            Ambiguous | Error(..) => {
+            ProjectionCandidateSet::Ambiguous | ProjectionCandidateSet::Error(..) => {
                 return false;
             }
         }
@@ -135,7 +134,7 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
         // We only ever get here when we moved from a single candidate
         // to ambiguous.
         let () = convert_to_ambiguous;
-        *self = Ambiguous;
+        *self = ProjectionCandidateSet::Ambiguous;
         false
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 18010603286..3b549244431 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -103,10 +103,7 @@ where
     let region_constraint_data = infcx.take_and_reset_region_constraints();
     let region_constraints = query_response::make_query_region_constraints(
         infcx.tcx,
-        region_obligations
-            .iter()
-            .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()))
-            .map(|(ty, r, cc)| (infcx.resolve_vars_if_possible(ty), r, cc)),
+        region_obligations,
         &region_constraint_data,
     );
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index e294f7839aa..7540cbe3fd1 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -110,6 +110,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::NormalizesTo(..)
+                | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
                 | ty::PredicateKind::AliasRelate(..) => {}
 
                 // We need to search through *all* WellFormed predicates
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index 18971c47831..22eeb285b37 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -21,19 +21,9 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
 
         if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) =
             key.value.predicate.kind().skip_binder()
+            && term.is_trivially_wf(tcx)
         {
-            match term.as_type()?.kind() {
-                ty::Param(_)
-                | ty::Bool
-                | ty::Char
-                | ty::Int(_)
-                | ty::Float(_)
-                | ty::Str
-                | ty::Uint(_) => {
-                    return Some(());
-                }
-                _ => {}
-            }
+            return Some(());
         }
 
         None
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 81ce58a93fa..cc188a280aa 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -19,7 +19,7 @@ use rustc_middle::{bug, span_bug};
 use tracing::{debug, instrument, trace};
 
 use super::SelectionCandidate::*;
-use super::{BuiltinImplConditions, SelectionCandidateSet, SelectionContext, TraitObligationStack};
+use super::{SelectionCandidateSet, SelectionContext, TraitObligationStack};
 use crate::traits::util;
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
@@ -75,27 +75,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     self.assemble_candidates_from_impls(obligation, &mut candidates);
 
                     // For other types, we'll use the builtin rules.
-                    let copy_conditions = self.copy_clone_conditions(obligation);
-                    self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
+                    self.assemble_builtin_copy_clone_candidate(
+                        obligation.predicate.self_ty().skip_binder(),
+                        &mut candidates,
+                    );
                 }
                 Some(LangItem::DiscriminantKind) => {
                     // `DiscriminantKind` is automatically implemented for every type.
-                    candidates.vec.push(BuiltinCandidate { has_nested: false });
+                    candidates.vec.push(BuiltinCandidate);
                 }
                 Some(LangItem::PointeeTrait) => {
                     // `Pointee` is automatically implemented for every type.
-                    candidates.vec.push(BuiltinCandidate { has_nested: false });
+                    candidates.vec.push(BuiltinCandidate);
                 }
                 Some(LangItem::Sized) => {
                     self.assemble_builtin_sized_candidate(
-                        obligation,
+                        obligation.predicate.self_ty().skip_binder(),
                         &mut candidates,
                         SizedTraitKind::Sized,
                     );
                 }
                 Some(LangItem::MetaSized) => {
                     self.assemble_builtin_sized_candidate(
-                        obligation,
+                        obligation.predicate.self_ty().skip_binder(),
                         &mut candidates,
                         SizedTraitKind::MetaSized,
                     );
@@ -357,15 +359,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &PolyTraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
-        let self_ty = obligation.self_ty().skip_binder();
-        // gen constructs get lowered to a special kind of coroutine that
-        // should directly `impl FusedIterator`.
-        if let ty::Coroutine(did, ..) = self_ty.kind()
-            && self.tcx().coroutine_is_gen(*did)
-        {
-            debug!(?self_ty, ?obligation, "assemble_fused_iterator_candidates",);
-
-            candidates.vec.push(BuiltinCandidate { has_nested: false });
+        if self.coroutine_is_gen(obligation.self_ty().skip_binder()) {
+            candidates.vec.push(BuiltinCandidate);
         }
     }
 
@@ -810,7 +805,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         hir::Movability::Movable => {
                             // Movable coroutines are always `Unpin`, so add an
                             // unconditional builtin candidate.
-                            candidates.vec.push(BuiltinCandidate { has_nested: false });
+                            candidates.vec.push(BuiltinCandidate);
                         }
                     }
                 }
@@ -1113,45 +1108,164 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
-    /// Assembles the `Sized` and `MetaSized` traits which are built-in to the language itself.
+    /// Assembles `Copy` and `Clone` candidates for built-in types with no libcore-defined
+    /// `Copy` or `Clone` impls.
     #[instrument(level = "debug", skip(self, candidates))]
-    fn assemble_builtin_sized_candidate(
+    fn assemble_builtin_copy_clone_candidate(
         &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
+        self_ty: Ty<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
-        sizedness: SizedTraitKind,
     ) {
-        match self.sizedness_conditions(obligation, sizedness) {
-            BuiltinImplConditions::Where(nested) => {
-                candidates
-                    .vec
-                    .push(SizedCandidate { has_nested: !nested.skip_binder().is_empty() });
+        match *self_ty.kind() {
+            // These impls are built-in because we cannot express sufficiently
+            // generic impls in libcore.
+            ty::FnDef(..)
+            | ty::FnPtr(..)
+            | ty::Error(_)
+            | ty::Tuple(..)
+            | ty::CoroutineWitness(..)
+            | ty::Pat(..) => {
+                candidates.vec.push(BuiltinCandidate);
+            }
+
+            // Implementations provided in libcore.
+            ty::Uint(_)
+            | ty::Int(_)
+            | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+            | ty::Bool
+            | ty::Float(_)
+            | ty::Char
+            | ty::RawPtr(..)
+            | ty::Never
+            | ty::Ref(_, _, hir::Mutability::Not)
+            | ty::Array(..) => {}
+
+            // FIXME(unsafe_binder): Should we conditionally
+            // (i.e. universally) implement copy/clone?
+            ty::UnsafeBinder(_) => {}
+
+            // Not `Sized`, which is a supertrait of `Copy`/`Clone`.
+            ty::Dynamic(..) | ty::Str | ty::Slice(..) | ty::Foreign(..) => {}
+
+            // Not `Copy` or `Clone` by design.
+            ty::Ref(_, _, hir::Mutability::Mut) => {}
+
+            ty::Coroutine(coroutine_def_id, args) => {
+                match self.tcx().coroutine_movability(coroutine_def_id) {
+                    hir::Movability::Static => {}
+                    hir::Movability::Movable => {
+                        if self.tcx().features().coroutine_clone() {
+                            let resolved_upvars =
+                                self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
+                            let resolved_witness =
+                                self.infcx.shallow_resolve(args.as_coroutine().witness());
+                            if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() {
+                                // Not yet resolved.
+                                candidates.ambiguous = true;
+                            } else {
+                                candidates.vec.push(BuiltinCandidate);
+                            }
+                        }
+                    }
+                }
+            }
+
+            ty::Closure(_, args) => {
+                let resolved_upvars =
+                    self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty());
+                if resolved_upvars.is_ty_var() {
+                    // Not yet resolved.
+                    candidates.ambiguous = true;
+                } else {
+                    candidates.vec.push(BuiltinCandidate);
+                }
+            }
+
+            ty::CoroutineClosure(_, args) => {
+                let resolved_upvars =
+                    self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty());
+                if resolved_upvars.is_ty_var() {
+                    // Not yet resolved.
+                    candidates.ambiguous = true;
+                } else {
+                    candidates.vec.push(BuiltinCandidate);
+                }
             }
-            BuiltinImplConditions::None => {}
-            BuiltinImplConditions::Ambiguous => {
+
+            // Fallback to whatever user-defined impls or param-env clauses exist in this case.
+            ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {}
+
+            ty::Infer(ty::TyVar(_)) => {
                 candidates.ambiguous = true;
             }
+
+            // Only appears when assembling higher-ranked `for<T> T: Clone`.
+            ty::Bound(..) => {}
+
+            ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+                bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
+            }
         }
     }
 
-    /// Assembles the trait which are built-in to the language itself:
-    /// e.g. `Copy` and `Clone`.
+    /// Assembles the `Sized` and `MetaSized` traits which are built-in to the language itself.
     #[instrument(level = "debug", skip(self, candidates))]
-    fn assemble_builtin_bound_candidates(
+    fn assemble_builtin_sized_candidate(
         &mut self,
-        conditions: BuiltinImplConditions<'tcx>,
+        self_ty: Ty<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
+        sizedness: SizedTraitKind,
     ) {
-        match conditions {
-            BuiltinImplConditions::Where(nested) => {
-                candidates
-                    .vec
-                    .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() });
+        match *self_ty.kind() {
+            // Always sized.
+            ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+            | ty::Uint(_)
+            | ty::Int(_)
+            | ty::Bool
+            | ty::Float(_)
+            | ty::FnDef(..)
+            | ty::FnPtr(..)
+            | ty::RawPtr(..)
+            | ty::Char
+            | ty::Ref(..)
+            | ty::Coroutine(..)
+            | ty::CoroutineWitness(..)
+            | ty::Array(..)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
+            | ty::Never
+            | ty::Error(_) => {
+                candidates.vec.push(SizedCandidate);
+            }
+
+            // Conditionally `Sized`.
+            ty::Tuple(..) | ty::Pat(..) | ty::Adt(..) | ty::UnsafeBinder(_) => {
+                candidates.vec.push(SizedCandidate);
             }
-            BuiltinImplConditions::None => {}
-            BuiltinImplConditions::Ambiguous => {
+
+            // `MetaSized` but not `Sized`.
+            ty::Str | ty::Slice(_) | ty::Dynamic(..) => match sizedness {
+                SizedTraitKind::Sized => {}
+                SizedTraitKind::MetaSized => {
+                    candidates.vec.push(SizedCandidate);
+                }
+            },
+
+            // Not `MetaSized` or `Sized`.
+            ty::Foreign(..) => {}
+
+            ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => {}
+
+            ty::Infer(ty::TyVar(_)) => {
                 candidates.ambiguous = true;
             }
+
+            // Only appears when assembling higher-ranked `for<T> T: Sized`.
+            ty::Bound(..) => {}
+
+            ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+                bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
+            }
         }
     }
 
@@ -1160,7 +1274,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         _obligation: &PolyTraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
-        candidates.vec.push(BuiltinCandidate { has_nested: false });
+        candidates.vec.push(BuiltinCandidate);
     }
 
     fn assemble_candidate_for_tuple(
@@ -1171,7 +1285,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
         match self_ty.kind() {
             ty::Tuple(_) => {
-                candidates.vec.push(BuiltinCandidate { has_nested: false });
+                candidates.vec.push(BuiltinCandidate);
             }
             ty::Infer(ty::TyVar(_)) => {
                 candidates.ambiguous = true;
@@ -1215,7 +1329,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let self_ty = self.infcx.resolve_vars_if_possible(obligation.self_ty());
 
         match self_ty.skip_binder().kind() {
-            ty::FnPtr(..) => candidates.vec.push(BuiltinCandidate { has_nested: false }),
+            ty::FnPtr(..) => candidates.vec.push(BuiltinCandidate),
             ty::Bool
             | ty::Char
             | ty::Int(_)
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 80f71c78993..ee8cef20279 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -11,25 +11,22 @@ use std::ops::ControlFlow;
 
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::lang_items::LangItem;
-use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
+use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
-use rustc_middle::ty::{
-    self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Upcast, elaborate,
-};
+use rustc_middle::ty::{self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use thin_vec::thin_vec;
 use tracing::{debug, instrument};
 
 use super::SelectionCandidate::{self, *};
-use super::{BuiltinImplConditions, PredicateObligations, SelectionContext};
+use super::{PredicateObligations, SelectionContext};
 use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
 use crate::traits::util::{self, closure_trait_ref_and_return_type};
 use crate::traits::{
     ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause,
-    PolyTraitObligation, PredicateObligation, Selection, SelectionError, SignatureMismatch,
-    TraitDynIncompatible, TraitObligation, Unimplemented,
+    PolyTraitObligation, PredicateObligation, Selection, SelectionError, TraitObligation,
 };
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
@@ -40,13 +37,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         candidate: SelectionCandidate<'tcx>,
     ) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
         Ok(match candidate {
-            SizedCandidate { has_nested } => {
-                let data = self.confirm_builtin_candidate(obligation, has_nested);
+            SizedCandidate => {
+                let data = self.confirm_builtin_candidate(obligation);
                 ImplSource::Builtin(BuiltinImplSource::Misc, data)
             }
 
-            BuiltinCandidate { has_nested } => {
-                let data = self.confirm_builtin_candidate(obligation, has_nested);
+            BuiltinCandidate => {
+                let data = self.confirm_builtin_candidate(obligation);
                 ImplSource::Builtin(BuiltinImplSource::Misc, data)
             }
 
@@ -176,7 +173,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let candidate = self.infcx.instantiate_binder_with_fresh_vars(
             obligation.cause.span,
-            HigherRankedType,
+            BoundRegionConversionTime::HigherRankedType,
             candidate,
         );
         let mut obligations = PredicateObligations::new();
@@ -194,7 +191,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 .at(&obligation.cause, obligation.param_env)
                 .eq(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
                 .map(|InferOk { obligations, .. }| obligations)
-                .map_err(|_| Unimplemented)?,
+                .map_err(|_| SelectionError::Unimplemented)?,
         );
 
         // FIXME(compiler-errors): I don't think this is needed.
@@ -252,50 +249,53 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
     fn confirm_builtin_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-        has_nested: bool,
     ) -> PredicateObligations<'tcx> {
-        debug!(?obligation, ?has_nested, "confirm_builtin_candidate");
-
+        debug!(?obligation, "confirm_builtin_candidate");
         let tcx = self.tcx();
-        let obligations = if has_nested {
-            let trait_def = obligation.predicate.def_id();
-            let conditions = match tcx.as_lang_item(trait_def) {
-                Some(LangItem::Sized) => {
-                    self.sizedness_conditions(obligation, SizedTraitKind::Sized)
-                }
-                Some(LangItem::MetaSized) => {
-                    self.sizedness_conditions(obligation, SizedTraitKind::MetaSized)
-                }
-                Some(LangItem::PointeeSized) => {
-                    bug!("`PointeeSized` is removing during lowering");
+        let trait_def = obligation.predicate.def_id();
+        let self_ty = self.infcx.shallow_resolve(
+            self.infcx.enter_forall_and_leak_universe(obligation.predicate.self_ty()),
+        );
+        let types = match tcx.as_lang_item(trait_def) {
+            Some(LangItem::Sized) => self.sizedness_conditions(self_ty, SizedTraitKind::Sized),
+            Some(LangItem::MetaSized) => {
+                self.sizedness_conditions(self_ty, SizedTraitKind::MetaSized)
+            }
+            Some(LangItem::PointeeSized) => {
+                bug!("`PointeeSized` is removing during lowering");
+            }
+            Some(LangItem::Copy | LangItem::Clone) => self.copy_clone_conditions(self_ty),
+            Some(LangItem::FusedIterator) => {
+                if self.coroutine_is_gen(self_ty) {
+                    ty::Binder::dummy(vec![])
+                } else {
+                    unreachable!("tried to assemble `FusedIterator` for non-gen coroutine");
                 }
-                Some(LangItem::Copy | LangItem::Clone) => self.copy_clone_conditions(obligation),
-                Some(LangItem::FusedIterator) => self.fused_iterator_conditions(obligation),
-                other => bug!("unexpected builtin trait {trait_def:?} ({other:?})"),
-            };
-            let BuiltinImplConditions::Where(types) = conditions else {
-                bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation);
-            };
-            let types = self.infcx.enter_forall_and_leak_universe(types);
-
-            let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
-            self.collect_predicates_for_types(
-                obligation.param_env,
-                cause,
-                obligation.recursion_depth + 1,
-                trait_def,
-                types,
-            )
-        } else {
-            PredicateObligations::new()
+            }
+            Some(
+                LangItem::Destruct
+                | LangItem::DiscriminantKind
+                | LangItem::FnPtrTrait
+                | LangItem::PointeeTrait
+                | LangItem::Tuple
+                | LangItem::Unpin,
+            ) => ty::Binder::dummy(vec![]),
+            other => bug!("unexpected builtin trait {trait_def:?} ({other:?})"),
         };
+        let types = self.infcx.enter_forall_and_leak_universe(types);
 
-        debug!(?obligations);
-
-        obligations
+        let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
+        self.collect_predicates_for_types(
+            obligation.param_env,
+            cause,
+            obligation.recursion_depth + 1,
+            trait_def,
+            types,
+        )
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -374,7 +374,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
         }
         let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else {
-            return Err(Unimplemented);
+            return Err(SelectionError::Unimplemented);
         };
 
         let dst = predicate.trait_ref.args.type_at(0);
@@ -386,7 +386,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             transmute_env.is_transmutable(rustc_transmute::Types { dst, src }, assume);
 
         let fully_flattened = match maybe_transmutable {
-            Answer::No(_) => Err(Unimplemented)?,
+            Answer::No(_) => Err(SelectionError::Unimplemented)?,
             Answer::If(cond) => flatten_answer_tree(self.tcx(), obligation, cond, assume),
             Answer::Yes => PredicateObligations::new(),
         };
@@ -409,6 +409,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             let self_ty =
                 obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
+            let self_ty = self.infcx.enter_forall_and_leak_universe(self_ty);
 
             let types = self.constituent_types_for_ty(self_ty)?;
             let types = self.infcx.enter_forall_and_leak_universe(types);
@@ -500,7 +501,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         });
         let object_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
             obligation.cause.span,
-            HigherRankedType,
+            BoundRegionConversionTime::HigherRankedType,
             object_trait_ref,
         );
         let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty);
@@ -513,7 +514,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let upcast_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
             obligation.cause.span,
-            HigherRankedType,
+            BoundRegionConversionTime::HigherRankedType,
             unnormalized_upcast_trait_ref,
         );
         let upcast_trait_ref = normalize_with_depth_to(
@@ -530,7 +531,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 .at(&obligation.cause, obligation.param_env)
                 .eq(DefineOpaqueTypes::No, trait_predicate.trait_ref, upcast_trait_ref)
                 .map(|InferOk { obligations, .. }| obligations)
-                .map_err(|_| Unimplemented)?,
+                .map_err(|_| SelectionError::Unimplemented)?,
         );
 
         // Check supertraits hold. This is so that their associated type bounds
@@ -905,7 +906,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let goal_kind =
             self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap();
 
-        // If we have not yet determiend the `ClosureKind` of the closure or coroutine-closure,
+        // If we have not yet determined the `ClosureKind` of the closure or coroutine-closure,
         // then additionally register an `AsyncFnKindHelper` goal which will fail if the kind
         // is constrained to an insufficient type later on.
         if let Some(closure_kind) = self.infcx.shallow_resolve(kind_ty).to_opt_closure_kind() {
@@ -962,7 +963,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         let found_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
             obligation.cause.span,
-            HigherRankedType,
+            BoundRegionConversionTime::HigherRankedType,
             found_trait_ref,
         );
         // Normalize the obligation and expected trait refs together, because why not
@@ -986,7 +987,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 obligations
             })
             .map_err(|terr| {
-                SignatureMismatch(Box::new(SignatureMismatchData {
+                SelectionError::SignatureMismatch(Box::new(SignatureMismatchData {
                     expected_trait_ref: obligation_trait_ref,
                     found_trait_ref,
                     terr,
@@ -1090,7 +1091,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
                     .sup(DefineOpaqueTypes::Yes, target, source_trait)
-                    .map_err(|_| Unimplemented)?;
+                    .map_err(|_| SelectionError::Unimplemented)?;
 
                 // Register one obligation for 'a: 'b.
                 let outlives = ty::OutlivesPredicate(r_a, r_b);
@@ -1109,7 +1110,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             (_, &ty::Dynamic(data, r, ty::Dyn)) => {
                 let mut object_dids = data.auto_traits().chain(data.principal_def_id());
                 if let Some(did) = object_dids.find(|did| !tcx.is_dyn_compatible(*did)) {
-                    return Err(TraitDynIncompatible(did));
+                    return Err(SelectionError::TraitDynIncompatible(did));
                 }
 
                 let predicate_to_obligation = |predicate| {
@@ -1148,38 +1149,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     ty::ClauseKind::TypeOutlives(outlives).upcast(tcx),
                 ));
 
-                // Require that all AFIT will return something that can be coerced into `dyn*`
-                // -- a shim will be responsible for doing the actual coercion to `dyn*`.
-                if let Some(principal) = data.principal() {
-                    for supertrait in
-                        elaborate::supertraits(tcx, principal.with_self_ty(tcx, source))
-                    {
-                        if tcx.is_trait_alias(supertrait.def_id()) {
-                            continue;
-                        }
-
-                        for &assoc_item in tcx.associated_item_def_ids(supertrait.def_id()) {
-                            if !tcx.is_impl_trait_in_trait(assoc_item) {
-                                continue;
-                            }
-
-                            // RPITITs with `Self: Sized` don't need to be checked.
-                            if tcx.generics_require_sized_self(assoc_item) {
-                                continue;
-                            }
-
-                            let pointer_like_goal = pointer_like_goal_for_rpitit(
-                                tcx,
-                                supertrait,
-                                assoc_item,
-                                &obligation.cause,
-                            );
-
-                            nested.push(predicate_to_obligation(pointer_like_goal.upcast(tcx)));
-                        }
-                    }
-                }
-
                 ImplSource::Builtin(BuiltinImplSource::Misc, nested)
             }
 
@@ -1189,7 +1158,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
                     .eq(DefineOpaqueTypes::Yes, b, a)
-                    .map_err(|_| Unimplemented)?;
+                    .map_err(|_| SelectionError::Unimplemented)?;
 
                 ImplSource::Builtin(BuiltinImplSource::Misc, obligations)
             }
@@ -1198,7 +1167,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             (&ty::Adt(def, args_a), &ty::Adt(_, args_b)) => {
                 let unsizing_params = tcx.unsizing_params_for_adt(def.did());
                 if unsizing_params.is_empty() {
-                    return Err(Unimplemented);
+                    return Err(SelectionError::Unimplemented);
                 }
 
                 let tail_field = def.non_enum_variant().tail();
@@ -1237,7 +1206,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
                     .eq(DefineOpaqueTypes::Yes, target, new_struct)
-                    .map_err(|_| Unimplemented)?;
+                    .map_err(|_| SelectionError::Unimplemented)?;
                 nested.extend(obligations);
 
                 // Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate.
@@ -1345,46 +1314,3 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         ImplSource::Builtin(BuiltinImplSource::Misc, obligations)
     }
 }
-
-/// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures)
-/// implements the `PointerLike` trait, which is a requirement for the RPITIT to be
-/// coercible to `dyn* Future`, which is itself a requirement for the RPITIT's parent
-/// trait to be coercible to `dyn Trait`.
-///
-/// We do this given a supertrait's substitutions, and then augment the substitutions
-/// with bound variables to compute the goal universally. Given that `PointerLike` has
-/// no region requirements (at least for the built-in pointer types), this shouldn't
-/// *really* matter, but it is the best choice for soundness.
-fn pointer_like_goal_for_rpitit<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    supertrait: ty::PolyTraitRef<'tcx>,
-    rpitit_item: DefId,
-    cause: &ObligationCause<'tcx>,
-) -> ty::PolyTraitRef<'tcx> {
-    let mut bound_vars = supertrait.bound_vars().to_vec();
-
-    let args = supertrait.skip_binder().args.extend_to(tcx, rpitit_item, |arg, _| match arg.kind {
-        ty::GenericParamDefKind::Lifetime => {
-            let kind = ty::BoundRegionKind::Named(arg.def_id, tcx.item_name(arg.def_id));
-            bound_vars.push(ty::BoundVariableKind::Region(kind));
-            ty::Region::new_bound(
-                tcx,
-                ty::INNERMOST,
-                ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
-            )
-            .into()
-        }
-        ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => {
-            unreachable!()
-        }
-    });
-
-    ty::Binder::bind_with_vars(
-        ty::TraitRef::new(
-            tcx,
-            tcx.require_lang_item(LangItem::PointerLike, cause.span),
-            [Ty::new_projection_from_args(tcx, rpitit_item, args)],
-        ),
-        tcx.mk_bound_variable_kinds(&bound_vars),
-    )
-}
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 9c0ccb26e53..10bcf861d35 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -28,7 +28,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
 use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
 use rustc_middle::ty::{
     self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt,
-    TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate,
+    TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, may_use_unstable_feature,
 };
 use rustc_span::{Symbol, sym};
 use tracing::{debug, instrument, trace};
@@ -39,7 +39,7 @@ use super::coherence::{self, Conflict};
 use super::project::ProjectionTermObligation;
 use super::util::closure_trait_ref_and_return_type;
 use super::{
-    ImplDerivedCause, Normalized, Obligation, ObligationCause, ObligationCauseCode, Overflow,
+    ImplDerivedCause, Normalized, Obligation, ObligationCause, ObligationCauseCode,
     PolyTraitObligation, PredicateObligation, Selection, SelectionError, SelectionResult,
     TraitQueryMode, const_evaluatable, project, util, wf,
 };
@@ -48,9 +48,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener};
 use crate::solve::InferCtxtSelectExt as _;
 use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
 use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
-use crate::traits::{
-    EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects, sizedness_fast_path,
-};
+use crate::traits::{EvaluateConstErr, ProjectionCacheKey, effects, sizedness_fast_path};
 
 mod _match;
 mod candidate_assembly;
@@ -190,18 +188,6 @@ struct EvaluatedCandidate<'tcx> {
     evaluation: EvaluationResult,
 }
 
-/// When does the builtin impl for `T: Trait` apply?
-#[derive(Debug)]
-enum BuiltinImplConditions<'tcx> {
-    /// The impl is conditional on `T1, T2, ...: Trait`.
-    Where(ty::Binder<'tcx, Vec<Ty<'tcx>>>),
-    /// There is no built-in impl. There may be some other
-    /// candidate (a where-clause or user-defined impl).
-    None,
-    /// It is unknown whether there is an impl.
-    Ambiguous,
-}
-
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
         SelectionContext {
@@ -454,8 +440,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
                 }
                 Ok(_) => Ok(None),
-                Err(OverflowError::Canonical) => Err(Overflow(OverflowError::Canonical)),
-                Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))),
+                Err(OverflowError::Canonical) => {
+                    Err(SelectionError::Overflow(OverflowError::Canonical))
+                }
+                Err(OverflowError::Error(e)) => {
+                    Err(SelectionError::Overflow(OverflowError::Error(e)))
+                }
             })
             .flat_map(Result::transpose)
             .collect::<Result<Vec<_>, _>>()?;
@@ -479,7 +469,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 debug!(?stack.obligation.predicate, "found error type in predicate, treating as ambiguous");
                 Ok(None)
             } else {
-                Err(Unimplemented)
+                Err(SelectionError::Unimplemented)
             }
         } else {
             let has_non_region_infer = stack.obligation.predicate.has_non_region_infer();
@@ -660,6 +650,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
 
                 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
+                    if term.is_trivially_wf(self.tcx()) {
+                        return Ok(EvaluatedToOk);
+                    }
+
                     // So, there is a bit going on here. First, `WellFormed` predicates
                     // are coinductive, like trait predicates with auto traits.
                     // This means that we need to detect if we have recursively
@@ -838,6 +832,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
                 }
 
+                ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
+                    if may_use_unstable_feature(self.infcx, obligation.param_env, symbol) {
+                        Ok(EvaluatedToOk)
+                    } else {
+                        Ok(EvaluatedToAmbig)
+                    }
+                }
+
                 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
                     match const_evaluatable::is_const_evaluatable(
                         self.infcx,
@@ -979,7 +981,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         }
                         ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
                         ty::ConstKind::Param(param_ct) => {
-                            param_ct.find_ty_from_env(obligation.param_env)
+                            param_ct.find_const_ty_from_env(obligation.param_env)
                         }
                     };
 
@@ -1222,7 +1224,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         match self.candidate_from_obligation(stack) {
             Ok(Some(c)) => self.evaluate_candidate(stack, &c),
             Ok(None) => Ok(EvaluatedToAmbig),
-            Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
+            Err(SelectionError::Overflow(OverflowError::Canonical)) => {
+                Err(OverflowError::Canonical)
+            }
             Err(..) => Ok(EvaluatedToErr),
         }
     }
@@ -1536,7 +1540,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 return Some(res);
             } else if cfg!(debug_assertions) {
                 match infcx.selection_cache.get(&(param_env, pred), tcx) {
-                    None | Some(Err(Overflow(OverflowError::Canonical))) => {}
+                    None | Some(Err(SelectionError::Overflow(OverflowError::Canonical))) => {}
                     res => bug!("unexpected local cache result: {res:?}"),
                 }
             }
@@ -1592,7 +1596,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
 
         if self.can_use_global_caches(param_env, cache_fresh_trait_pred) {
-            if let Err(Overflow(OverflowError::Canonical)) = candidate {
+            if let Err(SelectionError::Overflow(OverflowError::Canonical)) = candidate {
                 // Don't cache overflow globally; we only produce this in certain modes.
             } else {
                 debug!(?pred, ?candidate, "insert_candidate_cache global");
@@ -1826,7 +1830,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
 
         // We prefer `Sized` candidates over everything.
         let mut sized_candidates =
-            candidates.iter().filter(|c| matches!(c.candidate, SizedCandidate { has_nested: _ }));
+            candidates.iter().filter(|c| matches!(c.candidate, SizedCandidate));
         if let Some(sized_candidate) = sized_candidates.next() {
             // There should only ever be a single sized candidate
             // as they would otherwise overlap.
@@ -1978,8 +1982,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             // Don't use impl candidates which overlap with other candidates.
             // This should pretty much only ever happen with malformed impls.
             if candidates.iter().all(|c| match c.candidate {
-                SizedCandidate { has_nested: _ }
-                | BuiltinCandidate { has_nested: _ }
+                SizedCandidate
+                | BuiltinCandidate
                 | TransmutabilityCandidate
                 | AutoImplCandidate
                 | ClosureCandidate { .. }
@@ -2096,14 +2100,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
 impl<'tcx> SelectionContext<'_, 'tcx> {
     fn sizedness_conditions(
         &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
+        self_ty: Ty<'tcx>,
         sizedness: SizedTraitKind,
-    ) -> BuiltinImplConditions<'tcx> {
-        use self::BuiltinImplConditions::{Ambiguous, None, Where};
-
-        // NOTE: binder moved to (*)
-        let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
-
+    ) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> {
         match self_ty.kind() {
             ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
             | ty::Uint(_)
@@ -2121,60 +2120,44 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
             | ty::Never
-            | ty::Dynamic(_, _, ty::DynStar)
-            | ty::Error(_) => {
-                // safe for everything
-                Where(ty::Binder::dummy(Vec::new()))
-            }
+            | ty::Error(_) => ty::Binder::dummy(vec![]),
 
             ty::Str | ty::Slice(_) | ty::Dynamic(..) => match sizedness {
-                SizedTraitKind::Sized => None,
-                SizedTraitKind::MetaSized => Where(ty::Binder::dummy(Vec::new())),
+                SizedTraitKind::Sized => unreachable!("tried to assemble `Sized` for unsized type"),
+                SizedTraitKind::MetaSized => ty::Binder::dummy(vec![]),
             },
 
-            ty::Foreign(..) => None,
+            ty::Foreign(..) => unreachable!("tried to assemble `Sized` for unsized type"),
 
-            ty::Tuple(tys) => Where(
-                obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])),
-            ),
+            ty::Tuple(tys) => {
+                ty::Binder::dummy(tys.last().map_or_else(Vec::new, |&last| vec![last]))
+            }
 
-            ty::Pat(ty, _) => Where(obligation.predicate.rebind(vec![*ty])),
+            ty::Pat(ty, _) => ty::Binder::dummy(vec![*ty]),
 
             ty::Adt(def, args) => {
                 if let Some(crit) = def.sizedness_constraint(self.tcx(), sizedness) {
-                    // (*) binder moved here
-                    Where(obligation.predicate.rebind(vec![crit.instantiate(self.tcx(), args)]))
+                    ty::Binder::dummy(vec![crit.instantiate(self.tcx(), args)])
                 } else {
-                    Where(ty::Binder::dummy(Vec::new()))
+                    ty::Binder::dummy(vec![])
                 }
             }
 
-            // FIXME(unsafe_binders): This binder needs to be squashed
-            ty::UnsafeBinder(binder_ty) => Where(binder_ty.map_bound(|ty| vec![ty])),
+            ty::UnsafeBinder(binder_ty) => binder_ty.map_bound(|ty| vec![ty]),
 
-            ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None,
-            ty::Infer(ty::TyVar(_)) => Ambiguous,
-
-            // We can make this an ICE if/once we actually instantiate the trait obligation eagerly.
-            ty::Bound(..) => None,
-
-            ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
-                bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
+            ty::Alias(..)
+            | ty::Param(_)
+            | ty::Placeholder(..)
+            | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
+            | ty::Bound(..) => {
+                bug!("asked to assemble `Sized` of unexpected type: {:?}", self_ty);
             }
         }
     }
 
-    fn copy_clone_conditions(
-        &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
-    ) -> BuiltinImplConditions<'tcx> {
-        // NOTE: binder moved to (*)
-        let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
-
-        use self::BuiltinImplConditions::{Ambiguous, None, Where};
-
+    fn copy_clone_conditions(&mut self, self_ty: Ty<'tcx>) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> {
         match *self_ty.kind() {
-            ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Where(ty::Binder::dummy(Vec::new())),
+            ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => ty::Binder::dummy(vec![]),
 
             ty::Uint(_)
             | ty::Int(_)
@@ -2186,127 +2169,78 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             | ty::Never
             | ty::Ref(_, _, hir::Mutability::Not)
             | ty::Array(..) => {
-                // Implementations provided in libcore
-                None
+                unreachable!("tried to assemble `Sized` for type with libcore-provided impl")
             }
 
             // FIXME(unsafe_binder): Should we conditionally
             // (i.e. universally) implement copy/clone?
-            ty::UnsafeBinder(_) => None,
-
-            ty::Dynamic(..)
-            | ty::Str
-            | ty::Slice(..)
-            | ty::Foreign(..)
-            | ty::Ref(_, _, hir::Mutability::Mut) => None,
+            ty::UnsafeBinder(_) => unreachable!("tried to assemble `Sized` for unsafe binder"),
 
             ty::Tuple(tys) => {
                 // (*) binder moved here
-                Where(obligation.predicate.rebind(tys.iter().collect()))
+                ty::Binder::dummy(tys.iter().collect())
             }
 
             ty::Pat(ty, _) => {
                 // (*) binder moved here
-                Where(obligation.predicate.rebind(vec![ty]))
+                ty::Binder::dummy(vec![ty])
             }
 
             ty::Coroutine(coroutine_def_id, args) => {
                 match self.tcx().coroutine_movability(coroutine_def_id) {
-                    hir::Movability::Static => None,
+                    hir::Movability::Static => {
+                        unreachable!("tried to assemble `Sized` for static coroutine")
+                    }
                     hir::Movability::Movable => {
                         if self.tcx().features().coroutine_clone() {
-                            let resolved_upvars =
-                                self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
-                            let resolved_witness =
-                                self.infcx.shallow_resolve(args.as_coroutine().witness());
-                            if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() {
-                                // Not yet resolved.
-                                Ambiguous
-                            } else {
-                                let all = args
-                                    .as_coroutine()
+                            ty::Binder::dummy(
+                                args.as_coroutine()
                                     .upvar_tys()
                                     .iter()
                                     .chain([args.as_coroutine().witness()])
-                                    .collect::<Vec<_>>();
-                                Where(obligation.predicate.rebind(all))
-                            }
+                                    .collect::<Vec<_>>(),
+                            )
                         } else {
-                            None
+                            unreachable!(
+                                "tried to assemble `Sized` for coroutine without enabled feature"
+                            )
                         }
                     }
                 }
             }
 
-            ty::CoroutineWitness(def_id, args) => {
-                let hidden_types = rebind_coroutine_witness_types(
-                    self.infcx.tcx,
-                    def_id,
-                    args,
-                    obligation.predicate.bound_vars(),
-                );
-                Where(hidden_types)
-            }
+            ty::CoroutineWitness(def_id, args) => self
+                .infcx
+                .tcx
+                .coroutine_hidden_types(def_id)
+                .instantiate(self.infcx.tcx, args)
+                .map_bound(|witness| witness.types.to_vec()),
 
-            ty::Closure(_, args) => {
-                // (*) binder moved here
-                let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty());
-                if let ty::Infer(ty::TyVar(_)) = ty.kind() {
-                    // Not yet resolved.
-                    Ambiguous
-                } else {
-                    Where(obligation.predicate.rebind(args.as_closure().upvar_tys().to_vec()))
-                }
-            }
+            ty::Closure(_, args) => ty::Binder::dummy(args.as_closure().upvar_tys().to_vec()),
 
             ty::CoroutineClosure(_, args) => {
-                // (*) binder moved here
-                let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty());
-                if let ty::Infer(ty::TyVar(_)) = ty.kind() {
-                    // Not yet resolved.
-                    Ambiguous
-                } else {
-                    Where(
-                        obligation
-                            .predicate
-                            .rebind(args.as_coroutine_closure().upvar_tys().to_vec()),
-                    )
-                }
+                ty::Binder::dummy(args.as_coroutine_closure().upvar_tys().to_vec())
             }
 
-            ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {
-                // Fallback to whatever user-defined impls exist in this case.
-                None
-            }
-
-            ty::Infer(ty::TyVar(_)) => {
-                // Unbound type variable. Might or might not have
-                // applicable impls and so forth, depending on what
-                // those type variables wind up being bound to.
-                Ambiguous
-            }
-
-            // We can make this an ICE if/once we actually instantiate the trait obligation eagerly.
-            ty::Bound(..) => None,
-
-            ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            ty::Foreign(..)
+            | ty::Str
+            | ty::Slice(_)
+            | ty::Dynamic(..)
+            | ty::Adt(..)
+            | ty::Alias(..)
+            | ty::Param(..)
+            | ty::Placeholder(..)
+            | ty::Bound(..)
+            | ty::Ref(_, _, ty::Mutability::Mut)
+            | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
                 bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
             }
         }
     }
 
-    fn fused_iterator_conditions(
-        &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
-    ) -> BuiltinImplConditions<'tcx> {
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
-        if let ty::Coroutine(did, ..) = *self_ty.kind()
-            && self.tcx().coroutine_is_gen(did)
-        {
-            BuiltinImplConditions::Where(ty::Binder::dummy(Vec::new()))
-        } else {
-            BuiltinImplConditions::None
-        }
+    fn coroutine_is_gen(&mut self, self_ty: Ty<'tcx>) -> bool {
+        matches!(*self_ty.kind(), ty::Coroutine(did, ..)
+            if self.tcx().coroutine_is_gen(did))
     }
 
     /// For default impls, we need to break apart a type into its
@@ -2323,9 +2257,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
     #[instrument(level = "debug", skip(self), ret)]
     fn constituent_types_for_ty(
         &self,
-        t: ty::Binder<'tcx, Ty<'tcx>>,
+        t: Ty<'tcx>,
     ) -> Result<ty::Binder<'tcx, Vec<Ty<'tcx>>>, SelectionError<'tcx>> {
-        Ok(match *t.skip_binder().kind() {
+        Ok(match *t.kind() {
             ty::Uint(_)
             | ty::Int(_)
             | ty::Bool
@@ -2342,8 +2276,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             // `assemble_candidates_from_auto_impls`.
             ty::Foreign(..) => ty::Binder::dummy(Vec::new()),
 
-            // FIXME(unsafe_binders): Squash the double binder for now, I guess.
-            ty::UnsafeBinder(_) => return Err(SelectionError::Unimplemented),
+            ty::UnsafeBinder(ty) => ty.map_bound(|ty| vec![ty]),
 
             // Treat this like `struct str([u8]);`
             ty::Str => ty::Binder::dummy(vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)]),
@@ -2357,40 +2290,47 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 bug!("asked to assemble constituent types of unexpected type: {:?}", t);
             }
 
-            ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => t.rebind(vec![element_ty]),
+            ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => {
+                ty::Binder::dummy(vec![element_ty])
+            }
 
-            ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => t.rebind(vec![ty]),
+            ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => ty::Binder::dummy(vec![ty]),
 
             ty::Tuple(tys) => {
                 // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
-                t.rebind(tys.iter().collect())
+                ty::Binder::dummy(tys.iter().collect())
             }
 
             ty::Closure(_, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty());
-                t.rebind(vec![ty])
+                ty::Binder::dummy(vec![ty])
             }
 
             ty::CoroutineClosure(_, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty());
-                t.rebind(vec![ty])
+                ty::Binder::dummy(vec![ty])
             }
 
             ty::Coroutine(_, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
                 let witness = args.as_coroutine().witness();
-                t.rebind([ty].into_iter().chain(iter::once(witness)).collect())
+                ty::Binder::dummy([ty].into_iter().chain(iter::once(witness)).collect())
             }
 
-            ty::CoroutineWitness(def_id, args) => {
-                rebind_coroutine_witness_types(self.infcx.tcx, def_id, args, t.bound_vars())
-            }
+            ty::CoroutineWitness(def_id, args) => self
+                .infcx
+                .tcx
+                .coroutine_hidden_types(def_id)
+                .instantiate(self.infcx.tcx, args)
+                .map_bound(|witness| witness.types.to_vec()),
 
             // For `PhantomData<T>`, we pass `T`.
-            ty::Adt(def, args) if def.is_phantom_data() => t.rebind(args.types().collect()),
+            ty::Adt(def, args) if def.is_phantom_data() => {
+                ty::Binder::dummy(args.types().collect())
+            }
 
             ty::Adt(def, args) => {
-                t.rebind(def.all_fields().map(|f| f.ty(self.tcx(), args)).collect())
+                ty::Binder::dummy(def.all_fields().map(|f| f.ty(self.tcx(), args)).collect())
             }
 
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
@@ -2401,7 +2341,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                     // which enforces a DAG between the functions requiring
                     // the auto trait bounds in question.
                     match self.tcx().type_of_opaque(def_id) {
-                        Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]),
+                        Ok(ty) => ty::Binder::dummy(vec![ty.instantiate(self.tcx(), args)]),
                         Err(_) => {
                             return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
                         }
@@ -2873,23 +2813,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
     }
 }
 
-fn rebind_coroutine_witness_types<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-    args: ty::GenericArgsRef<'tcx>,
-    bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
-) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> {
-    let bound_coroutine_types = tcx.coroutine_hidden_types(def_id).skip_binder();
-    let shifted_coroutine_types =
-        tcx.shift_bound_var_indices(bound_vars.len(), bound_coroutine_types.skip_binder());
-    ty::Binder::bind_with_vars(
-        ty::EarlyBinder::bind(shifted_coroutine_types.types.to_vec()).instantiate(tcx, args),
-        tcx.mk_bound_variable_kinds_from_iter(
-            bound_vars.iter().chain(bound_coroutine_types.bound_vars()),
-        ),
-    )
-}
-
 impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
     fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> {
         TraitObligationStackList::with(self)
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index b30fadd3e5b..4bb12694c47 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -233,7 +233,7 @@ pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool
 ///
 /// For the purposes of const traits, we also check that the specializing
 /// impl is not more restrictive than the parent impl. That is, if the
-/// `parent_impl_def_id` is a const impl (conditionally based off of some `~const`
+/// `parent_impl_def_id` is a const impl (conditionally based off of some `[const]`
 /// bounds), then `specializing_impl_def_id` must also be const for the same
 /// set of types.
 #[instrument(skip(tcx), level = "debug")]
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 9452dca9a4f..19eb85506b6 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -273,8 +273,6 @@ impl<'tcx> Graph {
 
         // Descend the specialization tree, where `parent` is the current parent node.
         loop {
-            use self::Inserted::*;
-
             let insert_result = self.children.entry(parent).or_default().insert(
                 tcx,
                 impl_def_id,
@@ -283,11 +281,11 @@ impl<'tcx> Graph {
             )?;
 
             match insert_result {
-                BecameNewSibling(opt_lint) => {
+                Inserted::BecameNewSibling(opt_lint) => {
                     last_lint = opt_lint;
                     break;
                 }
-                ReplaceChildren(grand_children_to_be) => {
+                Inserted::ReplaceChildren(grand_children_to_be) => {
                     // We currently have
                     //
                     //     P
@@ -326,7 +324,7 @@ impl<'tcx> Graph {
                     }
                     break;
                 }
-                ShouldRecurseOn(new_parent) => {
+                Inserted::ShouldRecurseOn(new_parent) => {
                     parent = new_parent;
                 }
             }
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index a05bae53566..0c14b124e25 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -80,6 +80,7 @@ pub fn expand_trait_aliases<'tcx>(
             | ty::ClauseKind::ConstArgHasType(_, _)
             | ty::ClauseKind::WellFormed(_)
             | ty::ClauseKind::ConstEvaluatable(_)
+            | ty::ClauseKind::UnstableFeature(_)
             | ty::ClauseKind::HostEffect(..) => {}
         }
     }
@@ -368,16 +369,24 @@ pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
     // Proving `Sized`/`MetaSized`, very often on "obviously sized" types like
     // `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to
     // canonicalize and all that for such cases.
-    if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) =
+    if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
         predicate.kind().skip_binder()
+        && trait_pred.polarity == ty::PredicatePolarity::Positive
     {
-        let sizedness = match tcx.as_lang_item(trait_ref.def_id()) {
+        let sizedness = match tcx.as_lang_item(trait_pred.def_id()) {
             Some(LangItem::Sized) => SizedTraitKind::Sized,
             Some(LangItem::MetaSized) => SizedTraitKind::MetaSized,
             _ => return false,
         };
 
-        if trait_ref.self_ty().has_trivial_sizedness(tcx, sizedness) {
+        // FIXME(sized_hierarchy): this temporarily reverts the `sized_hierarchy` feature
+        // while a proper fix for `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs`
+        // is pending a proper fix
+        if !tcx.features().sized_hierarchy() && matches!(sizedness, SizedTraitKind::MetaSized) {
+            return true;
+        }
+
+        if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) {
             debug!("fast path -- trivial sizedness");
             return true;
         }
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index d4e6a23f0eb..adce9850b59 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -197,6 +197,7 @@ pub fn clause_obligations<'tcx>(
         ty::ClauseKind::ConstEvaluatable(ct) => {
             wf.add_wf_preds_for_term(ct.into());
         }
+        ty::ClauseKind::UnstableFeature(_) => {}
     }
 
     wf.normalize(infcx)
@@ -288,9 +289,9 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
             && let Some(&impl_item_id) =
                 tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.def_id)
             && let Some(impl_item) =
-                items.iter().find(|item| item.id.owner_id.to_def_id() == impl_item_id)
+                items.iter().find(|item| item.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).expect_type().span)
         } else {
             None
         }
@@ -1095,6 +1096,7 @@ pub fn object_region_bounds<'tcx>(
                 | ty::ClauseKind::Projection(_)
                 | ty::ClauseKind::ConstArgHasType(_, _)
                 | ty::ClauseKind::WellFormed(_)
+                | ty::ClauseKind::UnstableFeature(_)
                 | ty::ClauseKind::ConstEvaluatable(_) => None,
             }
         })