about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-07-24 22:02:52 +0000
committerMichael Goulet <michael@errs.io>2023-07-25 16:08:58 +0000
commita7ed9c1da7a3d850be67e5cf5ae2fcabeb42de3b (patch)
treee4c9749cc019bf479e963826e8ba599773d4220b
parentde81007d1310580e6060f2356f1938e45cafb92c (diff)
downloadrust-a7ed9c1da7a3d850be67e5cf5ae2fcabeb42de3b.tar.gz
rust-a7ed9c1da7a3d850be67e5cf5ae2fcabeb42de3b.zip
Make everything builtin!
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs5
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs11
-rw-r--r--compiler/rustc_middle/src/macros.rs4
-rw-r--r--compiler/rustc_middle/src/mir/basic_blocks.rs4
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs4
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs4
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs80
-rw-r--r--compiler/rustc_middle/src/traits/select.rs4
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs36
-rw-r--r--compiler/rustc_middle/src/ty/abstract_const.rs4
-rw-r--r--compiler/rustc_middle/src/ty/binding.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs115
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs36
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs171
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs150
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs88
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs5
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs19
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
23 files changed, 344 insertions, 443 deletions
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index d8b8fa927c7..15a7c0536cb 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -8,6 +8,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
+use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, InstanceDef, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArgKind, GenericArgs};
 use rustc_middle::ty::{TraitRef, TypeVisitableExt};
@@ -766,7 +767,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     };
 
                     match implsrc {
-                        Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
+                        Ok(Some(ImplSource::Param(ty::BoundConstness::ConstIfConst, _))) => {
                             debug!(
                                 "const_trait_impl: provided {:?} via where-clause in {:?}",
                                 trait_ref, param_env
@@ -774,7 +775,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             return;
                         }
                         // Closure: Fn{Once|Mut}
-                        Ok(Some(ImplSource::Builtin(_)))
+                        Ok(Some(ImplSource::Builtin(BuiltinImplSource::Misc, _)))
                             if trait_ref.self_ty().is_closure()
                                 && tcx.fn_trait_kind_from_def_id(trait_id).is_some() =>
                         {
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 0ef7ace6965..b3730dd2648 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -7,6 +7,7 @@ use rustc_hir::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir;
 use rustc_middle::mir::*;
+use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
 use rustc_trait_selection::traits::{
     self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
@@ -172,7 +173,8 @@ impl Qualif for NeedsNonConstDrop {
 
         if !matches!(
             impl_src,
-            ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
+            ImplSource::Builtin(BuiltinImplSource::Misc, _)
+                | ImplSource::Param(ty::BoundConstness::ConstIfConst, _)
         ) {
             // If our const destruct candidate is not ConstDestruct or implied by the param env,
             // then it's bad
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 9a25669ed31..56e485a4a3c 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -46,6 +46,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
 use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
 use rustc_infer::traits::{Obligation, PredicateObligation};
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
 };
@@ -687,12 +688,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 }
 
                 Ok(Some(impl_source)) => {
+                    // Some builtin coercions are still unstable so we detect
+                    // these here and emit a feature error if coercion doesn't fail
+                    // due to another reason.
                     match impl_source {
-                        traits::ImplSource::TraitUpcasting(..) => {
+                        traits::ImplSource::Builtin(
+                            BuiltinImplSource::TraitUpcasting { .. },
+                            _,
+                        ) => {
                             has_trait_upcasting_coercion =
                                 Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1)));
                         }
-                        traits::ImplSource::TupleUnsizing(_) => {
+                        traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
                             has_unsized_tuple_coercion = true;
                         }
                         _ => {}
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index cd1c6c330bc..fca16d8e509 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -43,7 +43,7 @@ macro_rules! span_bug {
 
 #[macro_export]
 macro_rules! CloneLiftImpls {
-    ($($ty:ty,)+) => {
+    ($($ty:ty),+ $(,)?) => {
         $(
             impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
                 type Lifted = Self;
@@ -59,7 +59,7 @@ macro_rules! CloneLiftImpls {
 /// allocated data** (i.e., don't need to be folded).
 #[macro_export]
 macro_rules! TrivialTypeTraversalImpls {
-    ($($ty:ty,)+) => {
+    ($($ty:ty),+ $(,)?) => {
         $(
             impl<'tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<'tcx>> for $ty {
                 fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$crate::ty::TyCtxt<'tcx>>>(
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index 7722e7b47cf..0ad17e819c7 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -178,9 +178,7 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
     }
 }
 
-TrivialTypeTraversalAndLiftImpls! {
-    Cache,
-}
+TrivialTypeTraversalAndLiftImpls! { Cache }
 
 impl<S: Encoder> Encodable<S> for Cache {
     #[inline]
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 372452ea29a..0b532c4badc 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -66,9 +66,7 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo {
     }
 }
 
-TrivialTypeTraversalAndLiftImpls! {
-    ErrorHandled,
-}
+TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
 
 pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
 pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 97f53a59fd6..3a958548515 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -706,9 +706,7 @@ pub enum BindingForm<'tcx> {
     RefForGuard,
 }
 
-TrivialTypeTraversalAndLiftImpls! {
-    BindingForm<'tcx>,
-}
+TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx> }
 
 mod binding_form_impl {
     use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index fb791d564a2..a2b33bb2737 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -649,46 +649,31 @@ pub enum ImplSource<'tcx, N> {
     /// for some type parameter. The `Vec<N>` represents the
     /// obligations incurred from normalizing the where-clause (if
     /// any).
-    Param(Vec<N>, ty::BoundConstness),
+    Param(ty::BoundConstness, Vec<N>),
 
-    /// Virtual calls through an object.
-    Object(ImplSourceObjectData<N>),
-
-    /// Successful resolution for a builtin trait.
-    Builtin(Vec<N>),
-
-    // Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`
-    TupleUnsizing(Vec<N>),
-
-    /// ImplSource for trait upcasting coercion
-    TraitUpcasting(ImplSourceTraitUpcastingData<N>),
+    /// Successful resolution for a builtin impl.
+    Builtin(BuiltinImplSource, Vec<N>),
 }
 
 impl<'tcx, N> ImplSource<'tcx, N> {
     pub fn nested_obligations(self) -> Vec<N> {
         match self {
             ImplSource::UserDefined(i) => i.nested,
-            ImplSource::Param(n, _) | ImplSource::Builtin(n) | ImplSource::TupleUnsizing(n) => n,
-            ImplSource::Object(d) => d.nested,
-            ImplSource::TraitUpcasting(d) => d.nested,
+            ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => n,
         }
     }
 
     pub fn borrow_nested_obligations(&self) -> &[N] {
         match self {
             ImplSource::UserDefined(i) => &i.nested,
-            ImplSource::Param(n, _) | ImplSource::Builtin(n) | ImplSource::TupleUnsizing(n) => &n,
-            ImplSource::Object(d) => &d.nested,
-            ImplSource::TraitUpcasting(d) => &d.nested,
+            ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => &n,
         }
     }
 
     pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] {
         match self {
             ImplSource::UserDefined(i) => &mut i.nested,
-            ImplSource::Param(n, _) | ImplSource::Builtin(n) | ImplSource::TupleUnsizing(n) => n,
-            ImplSource::Object(d) => &mut d.nested,
-            ImplSource::TraitUpcasting(d) => &mut d.nested,
+            ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => n,
         }
     }
 
@@ -702,20 +687,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
                 args: i.args,
                 nested: i.nested.into_iter().map(f).collect(),
             }),
-            ImplSource::Param(n, ct) => ImplSource::Param(n.into_iter().map(f).collect(), ct),
-            ImplSource::Builtin(n) => ImplSource::Builtin(n.into_iter().map(f).collect()),
-            ImplSource::TupleUnsizing(n) => {
-                ImplSource::TupleUnsizing(n.into_iter().map(f).collect())
-            }
-            ImplSource::Object(o) => ImplSource::Object(ImplSourceObjectData {
-                vtable_base: o.vtable_base,
-                nested: o.nested.into_iter().map(f).collect(),
-            }),
-            ImplSource::TraitUpcasting(d) => {
-                ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData {
-                    vtable_vptr_slot: d.vtable_vptr_slot,
-                    nested: d.nested.into_iter().map(f).collect(),
-                })
+            ImplSource::Param(ct, n) => ImplSource::Param(ct, n.into_iter().map(f).collect()),
+            ImplSource::Builtin(source, n) => {
+                ImplSource::Builtin(source, n.into_iter().map(f).collect())
             }
         }
     }
@@ -739,29 +713,31 @@ pub struct ImplSourceUserDefinedData<'tcx, N> {
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
-#[derive(TypeFoldable, TypeVisitable)]
-pub struct ImplSourceTraitUpcastingData<N> {
+#[derive(Copy, Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Debug)]
+pub enum BuiltinImplSource {
+    /// Some builtin impl we don't need to differentiate. This should be used
+    /// unless more specific information is necessary.
+    Misc,
+    /// A builtin impl for trait objects.
+    ///
+    /// The vtable is formed by concatenating together the method lists of
+    /// the base object trait and all supertraits, pointers to supertrait vtable will
+    /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
+    /// in that vtable.
+    Object { vtable_base: usize },
     /// The vtable is formed by concatenating together the method lists of
     /// the base object trait and all supertraits, pointers to supertrait vtable will
     /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
     /// within that vtable.
-    pub vtable_vptr_slot: Option<usize>,
-
-    pub nested: Vec<N>,
+    TraitUpcasting { vtable_vptr_slot: Option<usize> },
+    /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`.
+    ///
+    /// This needs to be a separate variant as it is still unstable and we need to emit
+    /// a feature error when using it on stable.
+    TupleUnsizing,
 }
 
-#[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, Lift)]
-#[derive(TypeFoldable, TypeVisitable)]
-pub struct ImplSourceObjectData<N> {
-    /// The vtable is formed by concatenating together the method lists of
-    /// the base object trait and all supertraits, pointers to supertrait vtable will
-    /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
-    /// in that vtable.
-    pub vtable_base: usize,
-
-    pub nested: Vec<N>,
-}
+TrivialTypeTraversalAndLiftImpls! { BuiltinImplSource }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
 pub enum ObjectSafetyViolation {
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index f2dda003b99..a90d58f5fc1 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -304,9 +304,7 @@ impl From<ErrorGuaranteed> for OverflowError {
     }
 }
 
-TrivialTypeTraversalAndLiftImpls! {
-    OverflowError,
-}
+TrivialTypeTraversalAndLiftImpls! { OverflowError }
 
 impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
     fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index b7bce05300d..530d1ec5d35 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -6,20 +6,16 @@ use std::fmt;
 
 impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            super::ImplSource::UserDefined(ref v) => write!(f, "{:?}", v),
+        match self {
+            super::ImplSource::UserDefined(v) => write!(f, "{:?}", v),
 
-            super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
-
-            super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
+            super::ImplSource::Builtin(source, d) => {
+                write!(f, "Builtin({source:?}, {d:?})")
+            }
 
-            super::ImplSource::Param(ref n, ct) => {
+            super::ImplSource::Param(ct, n) => {
                 write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
             }
-
-            super::ImplSource::TupleUnsizing(ref d) => write!(f, "{:?}", d),
-
-            super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
         }
     }
 }
@@ -33,23 +29,3 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceUserDefinedData<'tcx,
         )
     }
 }
-
-impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "ImplSourceTraitUpcastingData(vtable_vptr_slot={:?}, nested={:?})",
-            self.vtable_vptr_slot, self.nested
-        )
-    }
-}
-
-impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceObjectData<N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "ImplSourceObjectData(vtable_base={}, nested={:?})",
-            self.vtable_base, self.nested
-        )
-    }
-}
diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs
index 0364a620810..cdd8351499b 100644
--- a/compiler/rustc_middle/src/ty/abstract_const.rs
+++ b/compiler/rustc_middle/src/ty/abstract_const.rs
@@ -27,9 +27,7 @@ impl From<ErrorGuaranteed> for NotConstEvaluatable {
     }
 }
 
-TrivialTypeTraversalAndLiftImpls! {
-    NotConstEvaluatable,
-}
+TrivialTypeTraversalAndLiftImpls! { NotConstEvaluatable }
 
 pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed>;
 
diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs
index a5b05a4f9b5..2fec8ac9095 100644
--- a/compiler/rustc_middle/src/ty/binding.rs
+++ b/compiler/rustc_middle/src/ty/binding.rs
@@ -6,7 +6,7 @@ pub enum BindingMode {
     BindByValue(Mutability),
 }
 
-TrivialTypeTraversalAndLiftImpls! { BindingMode, }
+TrivialTypeTraversalAndLiftImpls! { BindingMode }
 
 impl BindingMode {
     pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 942f4088472..ab90db6ff58 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -3,17 +3,16 @@
 use super::search_graph::OverflowHandler;
 use super::{EvalCtxt, SolverMode};
 use crate::traits::coherence;
-use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
-use rustc_infer::traits::util::elaborate;
 use rustc_infer::traits::Reveal;
 use rustc_middle::traits::solve::inspect::CandidateKind;
 use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
+use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
-use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{fast_reject, TypeFoldable};
+use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
 use rustc_span::ErrorGuaranteed;
 use std::fmt::Debug;
 
@@ -89,17 +88,6 @@ pub(super) enum CandidateSource {
     AliasBound,
 }
 
-/// Records additional information about what kind of built-in impl this is.
-/// This should only be used by selection.
-#[derive(Debug, Clone, Copy)]
-pub(super) enum BuiltinImplSource {
-    TraitUpcasting,
-    TupleUnsize,
-    Object,
-    Misc,
-    Ambiguity,
-}
-
 /// Methods used to assemble candidates for either trait or projection goals.
 pub(super) trait GoalKind<'tcx>:
     TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display
@@ -282,20 +270,6 @@ pub(super) trait GoalKind<'tcx>:
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    /// Consider (possibly several) goals to upcast or unsize a type to another
-    /// type.
-    ///
-    /// The most common forms of unsizing are array to slice, and concrete (Sized)
-    /// type into a `dyn Trait`. ADTs and Tuples can also have their final field
-    /// unsized if it's generic.
-    ///
-    /// `dyn Trait1` can be unsized to `dyn Trait2` if they are the same trait, or
-    /// if `Trait2` is a (transitive) supertrait of `Trait2`.
-    fn consider_builtin_unsize_and_upcast_candidates(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
-        goal: Goal<'tcx, Self>,
-    ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)>;
-
     fn consider_builtin_discriminant_kind_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -310,6 +284,25 @@ pub(super) trait GoalKind<'tcx>:
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
+
+    /// Consider (possibly several) candidates to upcast or unsize a type to another
+    /// type.
+    ///
+    /// The most common forms of unsizing are array to slice, and concrete (Sized)
+    /// type into a `dyn Trait`. ADTs and Tuples can also have their final field
+    /// unsized if it's generic.
+    ///
+    /// `dyn Trait1` can be unsized to `dyn Trait2` if they are the same trait, or
+    /// if `Trait2` is a (transitive) supertrait of `Trait2`.
+    ///
+    /// We return the `BuiltinImplSource` for each candidate as it is needed
+    /// for unsize coercion in hir typeck and because it is difficult to
+    /// otherwise recompute this for codegen. This is a bit of a mess but the
+    /// easiest way to maintain the existing behavior for now.
+    fn consider_builtin_unsize_and_upcast_candidates(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)>;
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
@@ -343,7 +336,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     ) -> Option<Vec<Candidate<'tcx>>> {
         goal.predicate.self_ty().is_ty_var().then(|| {
             vec![Candidate {
-                source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
+                source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
                 result: self
                     .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
                     .unwrap(),
@@ -412,7 +405,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                             Certainty::Maybe(MaybeCause::Overflow),
                         )?;
                         Ok(vec![Candidate {
-                            source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
+                            source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
                             result,
                         }])
                     },
@@ -848,29 +841,47 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             ty::Dynamic(bounds, ..) => bounds,
         };
 
-        let own_bounds: FxIndexSet<_> =
-            bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)).collect();
-        for assumption in elaborate(tcx, own_bounds.iter().copied())
-            // we only care about bounds that match the `Self` type
-            .filter_only_self()
-        {
-            // FIXME: Predicates are fully elaborated in the object type's existential bounds
-            // list. We want to only consider these pre-elaborated projections, and not other
-            // projection predicates that we reach by elaborating the principal trait ref,
-            // since that'll cause ambiguity.
-            //
-            // We can remove this when we have implemented lifetime intersections in responses.
-            if assumption.as_projection_clause().is_some() && !own_bounds.contains(&assumption) {
-                continue;
+        // Consider all of the auto-trait and projection bounds, which don't
+        // need to be recorded as a `BuiltinImplSource::Object` since they don't
+        // really have a vtable base...
+        for bound in bounds {
+            match bound.skip_binder() {
+                ty::ExistentialPredicate::Trait(_) => {
+                    // Skip principal
+                }
+                ty::ExistentialPredicate::Projection(_)
+                | ty::ExistentialPredicate::AutoTrait(_) => {
+                    match G::consider_object_bound_candidate(
+                        self,
+                        goal,
+                        bound.with_self_ty(tcx, self_ty),
+                    ) {
+                        Ok(result) => candidates.push(Candidate {
+                            source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
+                            result,
+                        }),
+                        Err(NoSolution) => (),
+                    }
+                }
             }
+        }
 
-            match G::consider_object_bound_candidate(self, goal, assumption) {
-                Ok(result) => candidates.push(Candidate {
-                    source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object),
-                    result,
-                }),
-                Err(NoSolution) => (),
-            }
+        // FIXME: We only need to do *any* of this if we're considering a trait goal,
+        // since we don't need to look at any supertrait or anything if we are doing
+        // a projection goal.
+        if let Some(principal) = bounds.principal() {
+            let principal_trait_ref = principal.with_self_ty(tcx, self_ty);
+            self.walk_vtable(principal_trait_ref, |ecx, assumption, vtable_base, _| {
+                match G::consider_object_bound_candidate(ecx, goal, assumption.to_predicate(tcx)) {
+                    Ok(result) => candidates.push(Candidate {
+                        source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object {
+                            vtable_base,
+                        }),
+                        result,
+                    }),
+                    Err(NoSolution) => (),
+                }
+            });
         }
     }
 
@@ -890,7 +901,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                         .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
                     {
                         Ok(result) => candidates.push(Candidate {
-                            source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
+                            source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
                             result,
                         }),
                         // FIXME: This will be reachable at some point if we're in
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index 6e0aa08c307..b04d77f0a1a 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -25,6 +25,7 @@ use std::io::Write;
 use std::ops::ControlFlow;
 
 use crate::traits::specialization_graph;
+use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
 
 use super::inspect::ProofTreeBuilder;
 use super::search_graph::{self, OverflowHandler};
@@ -920,4 +921,39 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             Err(ErrorHandled::TooGeneric) => None,
         }
     }
+
+    /// Walk through the vtable of a principal trait ref, executing a `supertrait_visitor`
+    /// for every trait ref encountered (including the principal). Passes both the vtable
+    /// base and the (optional) vptr slot.
+    pub(super) fn walk_vtable(
+        &mut self,
+        principal: ty::PolyTraitRef<'tcx>,
+        mut supertrait_visitor: impl FnMut(&mut Self, ty::PolyTraitRef<'tcx>, usize, Option<usize>),
+    ) {
+        let tcx = self.tcx();
+        let mut offset = 0;
+        prepare_vtable_segments::<()>(tcx, principal, |segment| {
+            match segment {
+                VtblSegment::MetadataDSA => {
+                    offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
+                }
+                VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+                    let own_vtable_entries = count_own_vtable_entries(tcx, trait_ref);
+
+                    supertrait_visitor(
+                        self,
+                        trait_ref,
+                        offset,
+                        emit_vptr.then(|| offset + own_vtable_entries),
+                    );
+
+                    offset += own_vtable_entries;
+                    if emit_vptr {
+                        offset += 1;
+                    }
+                }
+            }
+            ControlFlow::Continue(())
+        });
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index cdfbaedb8c2..6045001510e 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -1,25 +1,20 @@
-use std::ops::ControlFlow;
-
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
-use rustc_infer::traits::util::supertraits;
+use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt};
 use rustc_infer::traits::{
     Obligation, PolyTraitObligation, PredicateObligation, Selection, SelectionResult, TraitEngine,
 };
 use rustc_middle::traits::solve::{CanonicalInput, Certainty, Goal};
 use rustc_middle::traits::{
-    ImplSource, ImplSourceObjectData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
-    ObligationCause, SelectionError,
+    BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, ObligationCause, SelectionError,
 };
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::DUMMY_SP;
 
-use crate::solve::assembly::{BuiltinImplSource, Candidate, CandidateSource};
+use crate::solve::assembly::{Candidate, CandidateSource};
 use crate::solve::eval_ctxt::{EvalCtxt, GenerateProofTree};
 use crate::solve::inspect::ProofTreeBuilder;
 use crate::solve::search_graph::OverflowHandler;
-use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
 use crate::traits::StructurallyNormalizeExt;
 use crate::traits::TraitEngineExt;
 
@@ -105,47 +100,26 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
                 rematch_impl(self, goal, def_id, nested_obligations)
             }
 
-            // Rematching the dyn upcast or object goal will instantiate the same nested
-            // goals that would have caused the ambiguity, so we can still make progress here
-            // regardless.
-            // FIXME: This doesn't actually check the object bounds hold here.
-            (
-                _,
-                CandidateSource::BuiltinImpl(
-                    BuiltinImplSource::Object | BuiltinImplSource::TraitUpcasting,
-                ),
-            ) => rematch_object(self, goal, nested_obligations),
-
-            (
-                Certainty::Maybe(_),
-                CandidateSource::BuiltinImpl(
-                    BuiltinImplSource::Misc | BuiltinImplSource::TupleUnsize,
-                ),
-            ) if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) => {
-                rematch_unsize(self, goal, nested_obligations)
-            }
-
-            (Certainty::Yes, CandidateSource::BuiltinImpl(BuiltinImplSource::TupleUnsize))
+            (Certainty::Maybe(_), CandidateSource::BuiltinImpl(src))
                 if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) =>
             {
-                Ok(Some(ImplSource::TupleUnsizing(nested_obligations)))
+                rematch_unsize(self, goal, nested_obligations, src)
             }
 
             // Technically some builtin impls have nested obligations, but if
             // `Certainty::Yes`, then they should've all been verified and don't
             // need re-checking.
-            (Certainty::Yes, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc)) => {
-                Ok(Some(ImplSource::Builtin(nested_obligations)))
+            (Certainty::Yes, CandidateSource::BuiltinImpl(src)) => {
+                Ok(Some(ImplSource::Builtin(src, nested_obligations)))
             }
 
             // It's fine not to do anything to rematch these, since there are no
             // nested obligations.
             (Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => {
-                Ok(Some(ImplSource::Param(nested_obligations, ty::BoundConstness::NotConst)))
+                Ok(Some(ImplSource::Param(ty::BoundConstness::NotConst, nested_obligations)))
             }
 
-            (_, CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity))
-            | (Certainty::Maybe(_), _) => Ok(None),
+            (Certainty::Maybe(_), _) => Ok(None),
         }
     }
 }
@@ -192,11 +166,12 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>(
         }
         (_, CandidateSource::ParamEnv(_)) => true,
 
+        // FIXME: we could prefer earlier vtable bases perhaps...
         (
-            CandidateSource::BuiltinImpl(BuiltinImplSource::Object),
-            CandidateSource::BuiltinImpl(BuiltinImplSource::Object),
+            CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
+            CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
         ) => false,
-        (_, CandidateSource::BuiltinImpl(BuiltinImplSource::Object)) => true,
+        (_, CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. })) => true,
 
         (CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_def_id)) => {
             tcx.specializes((other_def_id, victim_def_id))
@@ -234,108 +209,6 @@ fn rematch_impl<'tcx>(
     Ok(Some(ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, args, nested })))
 }
 
-fn rematch_object<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
-    mut nested: Vec<PredicateObligation<'tcx>>,
-) -> SelectionResult<'tcx, Selection<'tcx>> {
-    let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested);
-    let ty::Dynamic(data, _, source_kind) = *a_ty.kind() else { bug!() };
-    let source_trait_ref = data.principal().unwrap().with_self_ty(infcx.tcx, a_ty);
-
-    let (is_upcasting, target_trait_ref_unnormalized) =
-        if Some(goal.predicate.def_id()) == infcx.tcx.lang_items().unsize_trait() {
-            assert_eq!(source_kind, ty::Dyn, "cannot upcast dyn*");
-            let b_ty = structurally_normalize(
-                goal.predicate.trait_ref.args.type_at(1),
-                infcx,
-                goal.param_env,
-                &mut nested,
-            );
-            if let ty::Dynamic(data, _, ty::Dyn) = *b_ty.kind() {
-                // FIXME: We also need to ensure that the source lifetime outlives the
-                // target lifetime. This doesn't matter for codegen, though, and only
-                // *really* matters if the goal's certainty is ambiguous.
-                (true, data.principal().unwrap().with_self_ty(infcx.tcx, a_ty))
-            } else {
-                bug!()
-            }
-        } else {
-            (false, ty::Binder::dummy(goal.predicate.trait_ref))
-        };
-
-    let mut target_trait_ref = None;
-    for candidate_trait_ref in supertraits(infcx.tcx, source_trait_ref) {
-        let result = infcx.commit_if_ok(|_| {
-            infcx.at(&ObligationCause::dummy(), goal.param_env).eq(
-                DefineOpaqueTypes::No,
-                target_trait_ref_unnormalized,
-                candidate_trait_ref,
-            )
-
-            // FIXME: We probably should at least shallowly verify these...
-        });
-
-        match result {
-            Ok(InferOk { value: (), obligations }) => {
-                target_trait_ref = Some(candidate_trait_ref);
-                nested.extend(obligations);
-                break;
-            }
-            Err(_) => continue,
-        }
-    }
-
-    let target_trait_ref = target_trait_ref.unwrap();
-
-    let mut offset = 0;
-    let Some((vtable_base, vtable_vptr_slot)) =
-        prepare_vtable_segments(infcx.tcx, source_trait_ref, |segment| {
-            match segment {
-                VtblSegment::MetadataDSA => {
-                    offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
-                }
-                VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                    let own_vtable_entries = count_own_vtable_entries(infcx.tcx, trait_ref);
-
-                    if trait_ref == target_trait_ref {
-                        if emit_vptr {
-                            return ControlFlow::Break((
-                                offset,
-                                Some(offset + count_own_vtable_entries(infcx.tcx, trait_ref)),
-                            ));
-                        } else {
-                            return ControlFlow::Break((offset, None));
-                        }
-                    }
-
-                    offset += own_vtable_entries;
-                    if emit_vptr {
-                        offset += 1;
-                    }
-                }
-            }
-            ControlFlow::Continue(())
-        })
-    else {
-        bug!();
-    };
-
-    // If we're upcasting, get the offset of the vtable pointer, otherwise get
-    // the base of the vtable.
-    Ok(Some(if is_upcasting {
-        // If source and target trait def ids are identical,
-        // then we are simply removing auto traits.
-        if source_trait_ref.def_id() == target_trait_ref.def_id() {
-            ImplSource::Builtin(nested)
-        } else {
-            ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData { vtable_vptr_slot, nested })
-        }
-    } else {
-        ImplSource::Object(ImplSourceObjectData { vtable_base, nested })
-    }))
-}
-
 /// The `Unsize` trait is particularly important to coercion, so we try rematch it.
 /// NOTE: This must stay in sync with `consider_builtin_unsize_candidate` in trait
 /// goal assembly in the solver, both for soundness and in order to avoid ICEs.
@@ -343,6 +216,7 @@ fn rematch_unsize<'tcx>(
     infcx: &InferCtxt<'tcx>,
     goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
     mut nested: Vec<PredicateObligation<'tcx>>,
+    source: BuiltinImplSource,
 ) -> SelectionResult<'tcx, Selection<'tcx>> {
     let tcx = infcx.tcx;
     let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested);
@@ -379,6 +253,8 @@ fn rematch_unsize<'tcx>(
                 goal.param_env,
                 ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region)),
             ));
+
+            Ok(Some(ImplSource::Builtin(source, nested)))
         }
         // `[T; n]` -> `[T]` unsizing
         (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
@@ -389,6 +265,8 @@ fn rematch_unsize<'tcx>(
                     .expect("expected rematch to succeed")
                     .into_obligations(),
             );
+
+            Ok(Some(ImplSource::Builtin(source, nested)))
         }
         // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
         (&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args))
@@ -439,6 +317,8 @@ fn rematch_unsize<'tcx>(
                 goal.param_env,
                 ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
             ));
+
+            Ok(Some(ImplSource::Builtin(source, nested)))
         }
         // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
         (&ty::Tuple(a_tys), &ty::Tuple(b_tys))
@@ -467,15 +347,18 @@ fn rematch_unsize<'tcx>(
             ));
 
             // We need to be able to detect tuple unsizing to require its feature gate.
-            return Ok(Some(ImplSource::TupleUnsizing(nested)));
+            assert_eq!(
+                source,
+                BuiltinImplSource::TupleUnsizing,
+                "compiler-errors wants to know if this can ever be triggered..."
+            );
+            Ok(Some(ImplSource::Builtin(source, nested)))
         }
         // FIXME: We *could* ICE here if either:
         // 1. the certainty is `Certainty::Yes`,
         // 2. we're in codegen (which should mean `Certainty::Yes`).
-        _ => return Ok(None),
+        _ => Ok(None),
     }
-
-    Ok(Some(ImplSource::Builtin(nested)))
 }
 
 fn structurally_normalize<'tcx>(
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 0f4fec50427..03ade738bb6 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -1,6 +1,6 @@
 use crate::traits::specialization_graph;
 
-use super::assembly::{self, structural_traits, BuiltinImplSource};
+use super::assembly::{self, structural_traits};
 use super::EvalCtxt;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -10,6 +10,7 @@ use rustc_infer::traits::specialization_graph::LeafDef;
 use rustc_infer::traits::Reveal;
 use rustc_middle::traits::solve::inspect::CandidateKind;
 use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
+use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::ProjectionPredicate;
 use rustc_middle::ty::{self, Ty, TyCtxt};
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 7f813c58c84..24ea9b5ea12 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -1,15 +1,14 @@
 //! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
 
-use super::assembly::{self, structural_traits, BuiltinImplSource};
+use super::assembly::{self, structural_traits};
 use super::search_graph::OverflowHandler;
 use super::{EvalCtxt, SolverMode};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{LangItem, Movability};
 use rustc_infer::traits::query::NoSolution;
-use rustc_infer::traits::util::supertraits;
 use rustc_middle::traits::solve::inspect::CandidateKind;
-use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
-use rustc_middle::traits::Reveal;
+use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
+use rustc_middle::traits::{BuiltinImplSource, Reveal};
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
 use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
@@ -382,37 +381,48 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             let b_ty = match ecx
                 .normalize_non_self_ty(goal.predicate.trait_ref.args.type_at(1), goal.param_env)
             {
-                Ok(Some(b_ty)) if !b_ty.is_ty_var() => b_ty,
-                Ok(_) => {
-                    return vec![(
-                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+                Ok(Some(b_ty)) => {
+                    // If we have a type var, then bail with ambiguity.
+                    if b_ty.is_ty_var() {
+                        return vec![(
+                            ecx.evaluate_added_goals_and_make_canonical_response(
+                                Certainty::AMBIGUOUS,
+                            )
                             .unwrap(),
-                        BuiltinImplSource::Ambiguity,
+                            BuiltinImplSource::Misc,
+                        )];
+                    } else {
+                        b_ty
+                    }
+                }
+                Ok(None) => {
+                    return vec![(
+                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
+                            MaybeCause::Overflow,
+                        ))
+                        .unwrap(),
+                        BuiltinImplSource::Misc,
                     )];
                 }
                 Err(_) => return vec![],
             };
 
             let mut results = vec![];
+            results.extend(ecx.consider_builtin_dyn_upcast_candidates(goal.param_env, a_ty, b_ty));
             results.extend(
-                ecx.consider_builtin_dyn_upcast_candidates(goal.param_env, a_ty, b_ty)
+                ecx.consider_builtin_unsize_candidate(goal.with(ecx.tcx(), (a_ty, b_ty)))
                     .into_iter()
-                    .map(|resp| (resp, BuiltinImplSource::TraitUpcasting)),
-            );
-            results.extend(
-                ecx.consider_builtin_unsize_candidate(goal.param_env, a_ty, b_ty).into_iter().map(
-                    |resp| {
+                    .map(|resp| {
                         // If we're unsizing from tuple -> tuple, detect
                         let source =
                             if matches!((a_ty.kind(), b_ty.kind()), (ty::Tuple(..), ty::Tuple(..)))
                             {
-                                BuiltinImplSource::TupleUnsize
+                                BuiltinImplSource::TupleUnsizing
                             } else {
                                 BuiltinImplSource::Misc
                             };
                         (resp, source)
-                    },
-                ),
+                    }),
             );
 
             results
@@ -484,10 +494,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
 impl<'tcx> EvalCtxt<'_, 'tcx> {
     fn consider_builtin_unsize_candidate(
         &mut self,
-        param_env: ty::ParamEnv<'tcx>,
-        a_ty: Ty<'tcx>,
-        b_ty: Ty<'tcx>,
+        goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
     ) -> QueryResult<'tcx> {
+        let Goal { param_env, predicate: (a_ty, b_ty) } = goal;
         self.probe_candidate("builtin unsize").enter(|ecx| {
             let tcx = ecx.tcx();
             match (a_ty.kind(), b_ty.kind()) {
@@ -614,7 +623,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         a_ty: Ty<'tcx>,
         b_ty: Ty<'tcx>,
-    ) -> Vec<CanonicalResponse<'tcx>> {
+    ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
         if a_ty.is_ty_var() || b_ty.is_ty_var() {
             bug!("unexpected type variable in unsize goal")
         }
@@ -634,57 +643,64 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             return vec![];
         }
 
-        let mut unsize_dyn_to_principal = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
-            self.probe_candidate("upcast dyn to principle").enter(|ecx| -> Result<_, NoSolution> {
-                // Require that all of the trait predicates from A match B, except for
-                // the auto traits. We do this by constructing a new A type with B's
-                // auto traits, and equating these types.
-                let new_a_data = principal
-                    .into_iter()
-                    .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait))
-                    .chain(a_data.iter().filter(|a| {
-                        matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_))
-                    }))
-                    .chain(
-                        b_data
-                            .auto_traits()
-                            .map(ty::ExistentialPredicate::AutoTrait)
-                            .map(ty::Binder::dummy),
-                    );
-                let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data);
-                let new_a_ty = Ty::new_dynamic(tcx, new_a_data, b_region, ty::Dyn);
-
-                // We also require that A's lifetime outlives B's lifetime.
-                ecx.eq(param_env, new_a_ty, b_ty)?;
-                ecx.add_goal(Goal::new(
-                    tcx,
-                    param_env,
-                    ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
-                ));
-                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-            })
-        };
+        // Try to match `a_ty` against `b_ty`, replacing `a_ty`'s principal trait ref with
+        // the supertrait principal and subtyping the types.
+        let unsize_dyn_to_principal =
+            |ecx: &mut Self, principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
+                ecx.probe_candidate("upcast dyn to principle").enter(
+                    |ecx| -> Result<_, NoSolution> {
+                        // Require that all of the trait predicates from A match B, except for
+                        // the auto traits. We do this by constructing a new A type with B's
+                        // auto traits, and equating these types.
+                        let new_a_data = principal
+                            .into_iter()
+                            .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait))
+                            .chain(a_data.iter().filter(|a| {
+                                matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_))
+                            }))
+                            .chain(
+                                b_data
+                                    .auto_traits()
+                                    .map(ty::ExistentialPredicate::AutoTrait)
+                                    .map(ty::Binder::dummy),
+                            );
+                        let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data);
+                        let new_a_ty = Ty::new_dynamic(tcx, new_a_data, b_region, ty::Dyn);
+
+                        // We also require that A's lifetime outlives B's lifetime.
+                        ecx.eq(param_env, new_a_ty, b_ty)?;
+                        ecx.add_goal(Goal::new(
+                            tcx,
+                            param_env,
+                            ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
+                        ));
+                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                    },
+                )
+            };
 
         let mut responses = vec![];
         // If the principal def ids match (or are both none), then we're not doing
         // trait upcasting. We're just removing auto traits (or shortening the lifetime).
         if a_data.principal_def_id() == b_data.principal_def_id() {
-            if let Ok(response) = unsize_dyn_to_principal(a_data.principal()) {
-                responses.push(response);
-            }
-        } else if let Some(a_principal) = a_data.principal()
-            && let Some(b_principal) = b_data.principal()
-        {
-            for super_trait_ref in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)) {
-                if super_trait_ref.def_id() != b_principal.def_id() {
-                    continue;
-                }
-                let erased_trait_ref = super_trait_ref
-                    .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
-                if let Ok(response) = unsize_dyn_to_principal(Some(erased_trait_ref)) {
-                    responses.push(response);
-                }
+            if let Ok(resp) = unsize_dyn_to_principal(self, a_data.principal()) {
+                responses.push((resp, BuiltinImplSource::Misc));
             }
+        } else if let Some(a_principal) = a_data.principal() {
+            self.walk_vtable(
+                a_principal.with_self_ty(tcx, a_ty),
+                |ecx, new_a_principal, _, vtable_vptr_slot| {
+                    if let Ok(resp) = unsize_dyn_to_principal(
+                        ecx,
+                        Some(new_a_principal.map_bound(|trait_ref| {
+                            ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
+                        })),
+                    ) {
+                        responses
+                            .push((resp, BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }));
+                    }
+                },
+            );
         }
 
         responses
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 18470d520f7..a35dd1f1a59 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -4,7 +4,6 @@ use super::check_args_compatible;
 use super::specialization_graph;
 use super::translate_args;
 use super::util;
-use super::ImplSourceUserDefinedData;
 use super::MismatchedProjectionTypes;
 use super::Obligation;
 use super::ObligationCause;
@@ -13,6 +12,9 @@ use super::Selection;
 use super::SelectionContext;
 use super::SelectionError;
 use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
+use rustc_middle::traits::BuiltinImplSource;
+use rustc_middle::traits::ImplSource;
+use rustc_middle::traits::ImplSourceUserDefinedData;
 
 use crate::errors::InherentProjectionNormalizationOverflow;
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -1717,7 +1719,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
         };
 
         let eligible = match &impl_source {
-            super::ImplSource::UserDefined(impl_data) => {
+            ImplSource::UserDefined(impl_data) => {
                 // We have to be careful when projecting out of an
                 // impl because of specialization. If we are not in
                 // codegen (i.e., projection mode is not "any"), and the
@@ -1767,7 +1769,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     }
                 }
             }
-            super::ImplSource::Builtin(..) => {
+            ImplSource::Builtin(BuiltinImplSource::Misc, _) => {
                 // While a builtin impl may be known to exist, the associated type may not yet
                 // be known. Any type with multiple potential associated types is therefore
                 // not eligible.
@@ -1891,7 +1893,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     bug!("unexpected builtin trait with associated type: {trait_ref:?}")
                 }
             }
-            super::ImplSource::Param(..) => {
+            ImplSource::Param(..) => {
                 // This case tell us nothing about the value of an
                 // associated type. Consider:
                 //
@@ -1919,14 +1921,14 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                 // in `assemble_candidates_from_param_env`.
                 false
             }
-            super::ImplSource::Object(_) => {
+            ImplSource::Builtin(BuiltinImplSource::Object { .. }, _) => {
                 // Handled by the `Object` projection candidate. See
                 // `assemble_candidates_from_object_ty` for an explanation of
                 // why we special case object types.
                 false
             }
-            super::ImplSource::TraitUpcasting(_)
-            | super::ImplSource::TupleUnsizing(_) => {
+            ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
+            | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
                 // These traits have no associated types.
                 selcx.tcx().sess.delay_span_bug(
                     obligation.cause.span,
@@ -1986,8 +1988,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
     impl_source: Selection<'tcx>,
 ) -> Progress<'tcx> {
     match impl_source {
-        super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data),
-        super::ImplSource::Builtin(data) => {
+        ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data),
+        ImplSource::Builtin(BuiltinImplSource::Misc, data) => {
             let trait_def_id = obligation.predicate.trait_def_id(selcx.tcx());
             let lang_items = selcx.tcx().lang_items();
             if lang_items.gen_trait() == Some(trait_def_id) {
@@ -2004,10 +2006,10 @@ fn confirm_select_candidate<'cx, 'tcx>(
                 confirm_builtin_candidate(selcx, obligation, data)
             }
         }
-        super::ImplSource::Object(_)
-        | super::ImplSource::Param(..)
-        | super::ImplSource::TraitUpcasting(_)
-        | super::ImplSource::TupleUnsizing(_) => {
+        ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)
+        | ImplSource::Param(..)
+        | ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
+        | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
             // we don't create Select candidates with this kind of resolution
             span_bug!(
                 obligation.cause.span,
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index f423d40b994..92b9364adfa 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -11,7 +11,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
-use rustc_middle::traits::SelectionOutputTypeParameterMismatch;
+use rustc_middle::traits::{BuiltinImplSource, SelectionOutputTypeParameterMismatch};
 use rustc_middle::ty::{
     self, Binder, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
     TraitPredicate, TraitRef, Ty, TyCtxt, TypeVisitableExt,
@@ -26,9 +26,9 @@ use crate::traits::vtable::{
 };
 use crate::traits::{
     BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource,
-    ImplSourceObjectData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized,
-    Obligation, ObligationCause, OutputTypeParameterMismatch, PolyTraitObligation,
-    PredicateObligation, Selection, SelectionError, TraitNotObjectSafe, Unimplemented,
+    ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause,
+    OutputTypeParameterMismatch, PolyTraitObligation, PredicateObligation, Selection,
+    SelectionError, TraitNotObjectSafe, Unimplemented,
 };
 
 use super::BuiltinImplConditions;
@@ -48,18 +48,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let mut impl_src = match candidate {
             BuiltinCandidate { has_nested } => {
                 let data = self.confirm_builtin_candidate(obligation, has_nested);
-                ImplSource::Builtin(data)
+                ImplSource::Builtin(BuiltinImplSource::Misc, data)
             }
 
             TransmutabilityCandidate => {
                 let data = self.confirm_transmutability_candidate(obligation)?;
-                ImplSource::Builtin(data)
+                ImplSource::Builtin(BuiltinImplSource::Misc, data)
             }
 
             ParamCandidate(param) => {
                 let obligations =
                     self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
-                ImplSource::Param(obligations, param.skip_binder().constness)
+                ImplSource::Param(param.skip_binder().constness, obligations)
             }
 
             ImplCandidate(impl_def_id) => {
@@ -68,76 +68,57 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             AutoImplCandidate => {
                 let data = self.confirm_auto_impl_candidate(obligation)?;
-                ImplSource::Builtin(data)
+                ImplSource::Builtin(BuiltinImplSource::Misc, data)
             }
 
             ProjectionCandidate(idx, constness) => {
                 let obligations = self.confirm_projection_candidate(obligation, idx)?;
-                ImplSource::Param(obligations, constness)
+                ImplSource::Param(constness, obligations)
             }
 
-            ObjectCandidate(idx) => {
-                let data = self.confirm_object_candidate(obligation, idx)?;
-                ImplSource::Object(data)
-            }
+            ObjectCandidate(idx) => self.confirm_object_candidate(obligation, idx)?,
 
             ClosureCandidate { .. } => {
                 let vtable_closure = self.confirm_closure_candidate(obligation)?;
-                ImplSource::Builtin(vtable_closure)
+                ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure)
             }
 
             GeneratorCandidate => {
                 let vtable_generator = self.confirm_generator_candidate(obligation)?;
-                ImplSource::Builtin(vtable_generator)
+                ImplSource::Builtin(BuiltinImplSource::Misc, vtable_generator)
             }
 
             FutureCandidate => {
                 let vtable_future = self.confirm_future_candidate(obligation)?;
-                ImplSource::Builtin(vtable_future)
+                ImplSource::Builtin(BuiltinImplSource::Misc, vtable_future)
             }
 
             FnPointerCandidate { is_const } => {
                 let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
-                ImplSource::Builtin(data)
+                ImplSource::Builtin(BuiltinImplSource::Misc, data)
             }
 
             TraitAliasCandidate => {
                 let data = self.confirm_trait_alias_candidate(obligation);
-                ImplSource::Builtin(data)
+                ImplSource::Builtin(BuiltinImplSource::Misc, data)
             }
 
             BuiltinObjectCandidate => {
                 // This indicates something like `Trait + Send: Send`. In this case, we know that
                 // this holds because that's what the object type is telling us, and there's really
                 // no additional obligations to prove and no types in particular to unify, etc.
-                ImplSource::Builtin(Vec::new())
+                ImplSource::Builtin(BuiltinImplSource::Misc, Vec::new())
             }
 
-            BuiltinUnsizeCandidate => {
-                let source =
-                    self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
-                let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
-                let target = self.infcx.shallow_resolve(target);
-                let data = self.confirm_builtin_unsize_candidate(obligation, source, target)?;
-                // If the source and target are both unsize goals, then we need to signify that
-                // this is tuple unsizing so that during unsized coercion we require the proper
-                // feature gate.
-                if matches!(source.kind(), ty::Tuple(..)) && matches!(target.kind(), ty::Tuple(..))
-                {
-                    ImplSource::TupleUnsizing(data)
-                } else {
-                    ImplSource::Builtin(data)
-                }
-            }
+            BuiltinUnsizeCandidate => self.confirm_builtin_unsize_candidate(obligation)?,
 
             TraitUpcastingUnsizeCandidate(idx) => {
-                let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
-                ImplSource::TraitUpcasting(data)
+                self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?
             }
 
             ConstDestructCandidate(def_id) => {
                 let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
-                ImplSource::Builtin(data)
+                ImplSource::Builtin(BuiltinImplSource::Misc, data)
             }
         };
 
@@ -496,7 +477,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
         index: usize,
-    ) -> Result<ImplSourceObjectData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
         let tcx = self.tcx();
         debug!(?obligation, ?index, "confirm_object_candidate");
 
@@ -660,7 +641,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             (unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)),
         );
 
-        Ok(ImplSourceObjectData { vtable_base, nested })
+        Ok(ImplSource::Builtin(BuiltinImplSource::Object { vtable_base: vtable_base }, nested))
     }
 
     fn confirm_fn_pointer_candidate(
@@ -909,7 +890,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
         idx: usize,
-    ) -> Result<ImplSourceTraitUpcastingData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
         let tcx = self.tcx();
 
         // `assemble_candidates_for_unsizing` should ensure there are no late-bound
@@ -1006,19 +987,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let vtable_vptr_slot =
             prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback).unwrap();
 
-        Ok(ImplSourceTraitUpcastingData { vtable_vptr_slot, nested })
+        Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, nested))
     }
 
     fn confirm_builtin_unsize_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-        source: Ty<'tcx>,
-        target: Ty<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
         let tcx = self.tcx();
+
+        // `assemble_candidates_for_unsizing` should ensure there are no late-bound
+        // regions here. See the comment there for more details.
+        let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
+        let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
+        let target = self.infcx.shallow_resolve(target);
         debug!(?source, ?target, "confirm_builtin_unsize_candidate");
 
         let mut nested = vec![];
+        let src;
         match (source.kind(), target.kind()) {
             // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping).
             (&ty::Dynamic(ref data_a, r_a, dyn_a), &ty::Dynamic(ref data_b, r_b, dyn_b))
@@ -1062,6 +1048,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     obligation.param_env,
                     obligation.predicate.rebind(outlives),
                 ));
+
+                src = BuiltinImplSource::Misc;
             }
 
             // `T` -> `Trait`
@@ -1108,6 +1096,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 nested.push(predicate_to_obligation(
                     ty::Binder::dummy(ty::ClauseKind::TypeOutlives(outlives)).to_predicate(tcx),
                 ));
+
+                src = BuiltinImplSource::Misc;
             }
 
             // `[T; n]` -> `[T]`
@@ -1118,6 +1108,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     .eq(DefineOpaqueTypes::No, b, a)
                     .map_err(|_| Unimplemented)?;
                 nested.extend(obligations);
+
+                src = BuiltinImplSource::Misc;
             }
 
             // `Struct<T>` -> `Struct<U>`
@@ -1174,6 +1166,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     ),
                 );
                 nested.push(tail_unsize_obligation);
+
+                src = BuiltinImplSource::Misc;
             }
 
             // `(.., T)` -> `(.., U)`
@@ -1201,12 +1195,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     ty::TraitRef::new(tcx, obligation.predicate.def_id(), [a_last, b_last]),
                 );
                 nested.push(last_unsize_obligation);
+
+                src = BuiltinImplSource::TupleUnsizing;
             }
 
             _ => bug!("source: {source}, target: {target}"),
         };
 
-        Ok(nested)
+        Ok(ImplSource::Builtin(src, nested))
     }
 
     fn confirm_const_destruct_candidate(
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 7b34908c4be..3eab885a089 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -241,9 +241,9 @@ pub fn upcast_choices<'tcx>(
 /// Given an upcast trait object described by `object`, returns the
 /// index of the method `method_def_id` (which should be part of
 /// `object.upcast_trait_ref`) within the vtable for `object`.
-pub fn get_vtable_index_of_object_method<'tcx, N>(
+pub fn get_vtable_index_of_object_method<'tcx>(
     tcx: TyCtxt<'tcx>,
-    object: &super::ImplSourceObjectData<N>,
+    vtable_base: usize,
     method_def_id: DefId,
 ) -> Option<usize> {
     // Count number of methods preceding the one we are selecting and
@@ -252,7 +252,7 @@ pub fn get_vtable_index_of_object_method<'tcx, N>(
         .iter()
         .copied()
         .position(|def_id| def_id == method_def_id)
-        .map(|index| object.vtable_base + index)
+        .map(|index| vtable_base + index)
 }
 
 pub fn closure_trait_ref_and_return_type<'tcx>(
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index b4f614e3e22..c4cc89aa907 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -5,6 +5,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::traits::util::PredicateSet;
 use rustc_infer::traits::ImplSource;
 use rustc_middle::query::Providers;
+use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
@@ -384,8 +385,8 @@ pub(crate) fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>(
     let trait_ref = ty::TraitRef::new(tcx, unsize_trait_did, [source, target]);
 
     match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) {
-        Ok(ImplSource::TraitUpcasting(implsrc_traitcasting)) => {
-            implsrc_traitcasting.vtable_vptr_slot
+        Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, _)) => {
+            *vtable_vptr_slot
         }
         otherwise => bug!("expected TraitUpcasting candidate, got {otherwise:?}"),
     }
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 88eb33fee37..a21b5ef05e6 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -2,7 +2,7 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
-use rustc_middle::traits::CodegenObligationError;
+use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError};
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitableExt};
 use rustc_span::sym;
@@ -177,12 +177,15 @@ fn resolve_associated_item<'tcx>(
 
             Some(ty::Instance::new(leaf_def.item.def_id, args))
         }
-        traits::ImplSource::Object(ref data) => {
-            traits::get_vtable_index_of_object_method(tcx, data, trait_item_id).map(|index| {
-                Instance { def: ty::InstanceDef::Virtual(trait_item_id, index), args: rcvr_args }
-            })
+        traits::ImplSource::Builtin(BuiltinImplSource::Object { vtable_base }, _) => {
+            traits::get_vtable_index_of_object_method(tcx, *vtable_base, trait_item_id).map(
+                |index| Instance {
+                    def: ty::InstanceDef::Virtual(trait_item_id, index),
+                    args: rcvr_args,
+                },
+            )
         }
-        traits::ImplSource::Builtin(..) => {
+        traits::ImplSource::Builtin(BuiltinImplSource::Misc, _) => {
             let lang_items = tcx.lang_items();
             if Some(trait_ref.def_id) == lang_items.clone_trait() {
                 // FIXME(eddyb) use lang items for methods instead of names.
@@ -291,8 +294,8 @@ fn resolve_associated_item<'tcx>(
             }
         }
         traits::ImplSource::Param(..)
-        | traits::ImplSource::TraitUpcasting(_)
-        | traits::ImplSource::TupleUnsizing(_) => None,
+        | traits::ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
+        | traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => None,
     })
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 1c29d614fa3..e563e41ab2a 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -14,7 +14,7 @@ use rustc_middle::mir::{
     Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind,
     Terminator, TerminatorKind,
 };
-use rustc_middle::traits::{ImplSource, ObligationCause};
+use rustc_middle::traits::{ImplSource, ObligationCause, BuiltinImplSource};
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::{self, BoundConstness, GenericArgKind, TraitRef, Ty, TyCtxt};
 use rustc_semver::RustcVersion;
@@ -411,7 +411,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
 
     if !matches!(
         impl_src,
-        ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
+        ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(ty::BoundConstness::ConstIfConst, _)
     ) {
         return false;
     }