about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/solve/alias_relate.rs68
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs34
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs22
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs179
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs275
5 files changed, 280 insertions, 298 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index ca7fcfd8ca1..422a6ee3442 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -1,6 +1,5 @@
 use super::{EvalCtxt, SolverMode};
 use rustc_infer::traits::query::NoSolution;
-use rustc_middle::traits::solve::inspect::CandidateKind;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
 use rustc_middle::ty;
 
@@ -110,12 +109,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         direction: ty::AliasRelationDirection,
         invert: Invert,
     ) -> QueryResult<'tcx> {
-        self.probe(|r| CandidateKind::Candidate { name: "normalizes-to".into(), result: *r }).enter(
-            |ecx| {
-                ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?;
-                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-            },
-        )
+        self.probe_candidate("normalizes-to").enter(|ecx| {
+            ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?;
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        })
     }
 
     fn normalizes_to_inner(
@@ -156,20 +153,18 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         alias_rhs: ty::AliasTy<'tcx>,
         direction: ty::AliasRelationDirection,
     ) -> QueryResult<'tcx> {
-        self.probe(|r| CandidateKind::Candidate { name: "substs relate".into(), result: *r }).enter(
-            |ecx| {
-                match direction {
-                    ty::AliasRelationDirection::Equate => {
-                        ecx.eq(param_env, alias_lhs, alias_rhs)?;
-                    }
-                    ty::AliasRelationDirection::Subtype => {
-                        ecx.sub(param_env, alias_lhs, alias_rhs)?;
-                    }
+        self.probe_candidate("substs relate").enter(|ecx| {
+            match direction {
+                ty::AliasRelationDirection::Equate => {
+                    ecx.eq(param_env, alias_lhs, alias_rhs)?;
+                }
+                ty::AliasRelationDirection::Subtype => {
+                    ecx.sub(param_env, alias_lhs, alias_rhs)?;
                 }
+            }
 
-                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-            },
-        )
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        })
     }
 
     fn assemble_bidirectional_normalizes_to_candidate(
@@ -179,23 +174,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         rhs: ty::Term<'tcx>,
         direction: ty::AliasRelationDirection,
     ) -> QueryResult<'tcx> {
-        self.probe(|r| CandidateKind::Candidate { name: "bidir normalizes-to".into(), result: *r })
-            .enter(|ecx| {
-                ecx.normalizes_to_inner(
-                    param_env,
-                    lhs.to_alias_ty(ecx.tcx()).unwrap(),
-                    rhs,
-                    direction,
-                    Invert::No,
-                )?;
-                ecx.normalizes_to_inner(
-                    param_env,
-                    rhs.to_alias_ty(ecx.tcx()).unwrap(),
-                    lhs,
-                    direction,
-                    Invert::Yes,
-                )?;
-                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-            })
+        self.probe_candidate("bidir normalizes-to").enter(|ecx| {
+            ecx.normalizes_to_inner(
+                param_env,
+                lhs.to_alias_ty(ecx.tcx()).unwrap(),
+                rhs,
+                direction,
+                Invert::No,
+            )?;
+            ecx.normalizes_to_inner(
+                param_env,
+                rhs.to_alias_ty(ecx.tcx()).unwrap(),
+                lhs,
+                direction,
+                Invert::Yes,
+            )?;
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        })
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index 6b7be73b631..f98997e115d 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -9,7 +9,7 @@ use rustc_infer::infer::{
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::traits::solve::inspect::{self, CandidateKind};
+use rustc_middle::traits::solve::inspect;
 use rustc_middle::traits::solve::{
     CanonicalInput, CanonicalResponse, Certainty, IsNormalizesToHack, MaybeCause,
     PredefinedOpaques, PredefinedOpaquesData, QueryResult,
@@ -880,25 +880,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             if candidate_key.def_id != key.def_id {
                 continue;
             }
-            values.extend(
-                self.probe(|r| CandidateKind::Candidate {
-                    name: "opaque type storage".into(),
-                    result: *r,
-                })
-                .enter(|ecx| {
-                    for (a, b) in std::iter::zip(candidate_key.substs, key.substs) {
-                        ecx.eq(param_env, a, b)?;
-                    }
-                    ecx.eq(param_env, candidate_ty, ty)?;
-                    ecx.add_item_bounds_for_hidden_type(
-                        candidate_key.def_id.to_def_id(),
-                        candidate_key.substs,
-                        param_env,
-                        candidate_ty,
-                    );
-                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                }),
-            );
+            values.extend(self.probe_candidate("opaque type storage").enter(|ecx| {
+                for (a, b) in std::iter::zip(candidate_key.substs, key.substs) {
+                    ecx.eq(param_env, a, b)?;
+                }
+                ecx.eq(param_env, candidate_ty, ty)?;
+                ecx.add_item_bounds_for_hidden_type(
+                    candidate_key.def_id.to_def_id(),
+                    candidate_key.substs,
+                    param_env,
+                    candidate_ty,
+                );
+                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+            }));
         }
         values
     }
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
index 5d912fc039d..4477ea7d501 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
@@ -1,5 +1,5 @@
 use super::EvalCtxt;
-use rustc_middle::traits::solve::inspect;
+use rustc_middle::traits::solve::{inspect, QueryResult};
 use std::marker::PhantomData;
 
 pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> {
@@ -44,4 +44,24 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     {
         ProbeCtxt { ecx: self, probe_kind, _result: PhantomData }
     }
+
+    pub(in crate::solve) fn probe_candidate(
+        &mut self,
+        name: &'static str,
+    ) -> ProbeCtxt<
+        '_,
+        'a,
+        'tcx,
+        impl FnOnce(&QueryResult<'tcx>) -> inspect::CandidateKind<'tcx>,
+        QueryResult<'tcx>,
+    > {
+        ProbeCtxt {
+            ecx: self,
+            probe_kind: move |result: &QueryResult<'tcx>| inspect::CandidateKind::Candidate {
+                name: name.to_string(),
+                result: *result,
+            },
+            _result: PhantomData,
+        }
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index cbea8009f02..14fff4ab661 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -112,23 +112,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
     ) -> QueryResult<'tcx> {
         if let Some(projection_pred) = assumption.as_projection_clause() {
             if projection_pred.projection_def_id() == goal.predicate.def_id() {
-                ecx.probe(|r| CandidateKind::Candidate { name: "assumption".into(), result: *r })
-                    .enter(|ecx| {
-                        let assumption_projection_pred =
-                            ecx.instantiate_binder_with_infer(projection_pred);
-                        ecx.eq(
-                            goal.param_env,
-                            goal.predicate.projection_ty,
-                            assumption_projection_pred.projection_ty,
-                        )?;
-                        ecx.eq(
-                            goal.param_env,
-                            goal.predicate.term,
-                            assumption_projection_pred.term,
-                        )
+                ecx.probe_candidate("assumption").enter(|ecx| {
+                    let assumption_projection_pred =
+                        ecx.instantiate_binder_with_infer(projection_pred);
+                    ecx.eq(
+                        goal.param_env,
+                        goal.predicate.projection_ty,
+                        assumption_projection_pred.projection_ty,
+                    )?;
+                    ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
                         .expect("expected goal term to be fully unconstrained");
-                        then(ecx)
-                    })
+                    then(ecx)
+                })
             } else {
                 Err(NoSolution)
             }
@@ -329,69 +324,53 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
         let tcx = ecx.tcx();
-        ecx.probe(|r| CandidateKind::Candidate { name: "builtin pointee".into(), result: *r })
-            .enter(|ecx| {
-                let metadata_ty = match goal.predicate.self_ty().kind() {
-                    ty::Bool
-                    | ty::Char
-                    | ty::Int(..)
-                    | ty::Uint(..)
-                    | ty::Float(..)
-                    | ty::Array(..)
-                    | ty::RawPtr(..)
-                    | ty::Ref(..)
-                    | ty::FnDef(..)
-                    | ty::FnPtr(..)
-                    | ty::Closure(..)
-                    | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
-                    | ty::Generator(..)
-                    | ty::GeneratorWitness(..)
-                    | ty::GeneratorWitnessMIR(..)
-                    | ty::Never
-                    | ty::Foreign(..) => tcx.types.unit,
-
-                    ty::Error(e) => tcx.ty_error(*e),
-
-                    ty::Str | ty::Slice(_) => tcx.types.usize,
-
-                    ty::Dynamic(_, _, _) => {
-                        let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
-                        tcx.type_of(dyn_metadata)
-                            .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
-                    }
-
-                    ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
-                        // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
-                        let sized_predicate = ty::TraitRef::from_lang_item(
-                            tcx,
-                            LangItem::Sized,
-                            DUMMY_SP,
-                            [ty::GenericArg::from(goal.predicate.self_ty())],
-                        );
-                        ecx.add_goal(goal.with(tcx, sized_predicate));
-                        tcx.types.unit
-                    }
+        ecx.probe_candidate("builtin pointee").enter(|ecx| {
+            let metadata_ty = match goal.predicate.self_ty().kind() {
+                ty::Bool
+                | ty::Char
+                | ty::Int(..)
+                | ty::Uint(..)
+                | ty::Float(..)
+                | ty::Array(..)
+                | ty::RawPtr(..)
+                | ty::Ref(..)
+                | ty::FnDef(..)
+                | ty::FnPtr(..)
+                | ty::Closure(..)
+                | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
+                | ty::Generator(..)
+                | ty::GeneratorWitness(..)
+                | ty::GeneratorWitnessMIR(..)
+                | ty::Never
+                | ty::Foreign(..) => tcx.types.unit,
+
+                ty::Error(e) => tcx.ty_error(*e),
+
+                ty::Str | ty::Slice(_) => tcx.types.usize,
+
+                ty::Dynamic(_, _, _) => {
+                    let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
+                    tcx.type_of(dyn_metadata)
+                        .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
+                }
 
-                    ty::Adt(def, substs) if def.is_struct() => {
-                        match def.non_enum_variant().fields.raw.last() {
-                            None => tcx.types.unit,
-                            Some(field_def) => {
-                                let self_ty = field_def.ty(tcx, substs);
-                                ecx.add_goal(goal.with(
-                                    tcx,
-                                    ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
-                                ));
-                                return ecx.evaluate_added_goals_and_make_canonical_response(
-                                    Certainty::Yes,
-                                );
-                            }
-                        }
-                    }
-                    ty::Adt(_, _) => tcx.types.unit,
+                ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
+                    // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
+                    let sized_predicate = ty::TraitRef::from_lang_item(
+                        tcx,
+                        LangItem::Sized,
+                        DUMMY_SP,
+                        [ty::GenericArg::from(goal.predicate.self_ty())],
+                    );
+                    ecx.add_goal(goal.with(tcx, sized_predicate));
+                    tcx.types.unit
+                }
 
-                    ty::Tuple(elements) => match elements.last() {
+                ty::Adt(def, substs) if def.is_struct() => {
+                    match def.non_enum_variant().fields.raw.last() {
                         None => tcx.types.unit,
-                        Some(&self_ty) => {
+                        Some(field_def) => {
+                            let self_ty = field_def.ty(tcx, substs);
                             ecx.add_goal(goal.with(
                                 tcx,
                                 ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
@@ -399,21 +378,35 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                             return ecx
                                 .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
                         }
-                    },
-
-                    ty::Infer(
-                        ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
-                    )
-                    | ty::Bound(..) => bug!(
-                        "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
-                        goal.predicate.self_ty()
-                    ),
-                };
+                    }
+                }
+                ty::Adt(_, _) => tcx.types.unit,
 
-                ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into())
-                    .expect("expected goal term to be fully unconstrained");
-                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-            })
+                ty::Tuple(elements) => match elements.last() {
+                    None => tcx.types.unit,
+                    Some(&self_ty) => {
+                        ecx.add_goal(goal.with(
+                            tcx,
+                            ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
+                        ));
+                        return ecx
+                            .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
+                    }
+                },
+
+                ty::Infer(
+                    ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
+                )
+                | ty::Bound(..) => bug!(
+                    "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
+                    goal.predicate.self_ty()
+                ),
+            };
+
+            ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into())
+                .expect("expected goal term to be fully unconstrained");
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        })
     }
 
     fn consider_builtin_future_candidate(
@@ -548,11 +541,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
             ),
         };
 
-        ecx.probe(|r| CandidateKind::Candidate {
-            name: "builtin discriminant kind".into(),
-            result: *r,
-        })
-        .enter(|ecx| {
+        ecx.probe_candidate("builtin discriminant kind").enter(|ecx| {
             ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into())
                 .expect("expected goal term to be fully unconstrained");
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 18fec6d9c89..a2eb223bc26 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -6,7 +6,6 @@ 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::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
@@ -62,7 +61,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             },
         };
 
-        ecx.probe(|r| CandidateKind::Candidate { name: "impl".into(), result: *r }).enter(|ecx| {
+        ecx.probe_candidate("impl").enter(|ecx| {
             let impl_substs = ecx.fresh_substs_for_item(impl_def_id);
             let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
 
@@ -90,16 +89,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                 && trait_clause.polarity() == goal.predicate.polarity
             {
                 // FIXME: Constness
-                ecx.probe(|r| CandidateKind::Candidate { name: "assumption".into(), result: *r })
-                    .enter(|ecx| {
-                        let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
-                        ecx.eq(
-                            goal.param_env,
-                            goal.predicate.trait_ref,
-                            assumption_trait_pred.trait_ref,
-                        )?;
-                        then(ecx)
-                    })
+                ecx.probe_candidate("assumption").enter(|ecx| {
+                    let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
+                    ecx.eq(
+                        goal.param_env,
+                        goal.predicate.trait_ref,
+                        assumption_trait_pred.trait_ref,
+                    )?;
+                    then(ecx)
+                })
             } else {
                 Err(NoSolution)
             }
@@ -136,15 +134,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
 
         let tcx = ecx.tcx();
 
-        ecx.probe(|r| CandidateKind::Candidate { name: "trait alias".into(), result: *r }).enter(
-            |ecx| {
-                let nested_obligations = tcx
-                    .predicates_of(goal.predicate.def_id())
-                    .instantiate(tcx, goal.predicate.trait_ref.substs);
-                ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)));
-                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-            },
-        )
+        ecx.probe_candidate("trait alias").enter(|ecx| {
+            let nested_obligations = tcx
+                .predicates_of(goal.predicate.def_id())
+                .instantiate(tcx, goal.predicate.trait_ref.substs);
+            ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)));
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        })
     }
 
     fn consider_builtin_sized_candidate(
@@ -350,115 +346,109 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         if b_ty.is_ty_var() {
             return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
         }
-        ecx.probe(|r| CandidateKind::Candidate { name: "builtin unsize".into(), result: *r }).enter(
-            |ecx| {
-                match (a_ty.kind(), b_ty.kind()) {
-                    // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`
-                    (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => {
-                        // Dyn upcasting is handled separately, since due to upcasting,
-                        // when there are two supertraits that differ by substs, we
-                        // may return more than one query response.
-                        Err(NoSolution)
+        ecx.probe_candidate("builtin unsize").enter(|ecx| {
+            match (a_ty.kind(), b_ty.kind()) {
+                // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`
+                (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => {
+                    // Dyn upcasting is handled separately, since due to upcasting,
+                    // when there are two supertraits that differ by substs, we
+                    // may return more than one query response.
+                    Err(NoSolution)
+                }
+                // `T` -> `dyn Trait` unsizing
+                (_, &ty::Dynamic(data, region, ty::Dyn)) => {
+                    // Can only unsize to an object-safe type
+                    if data
+                        .principal_def_id()
+                        .is_some_and(|def_id| !tcx.check_is_object_safe(def_id))
+                    {
+                        return Err(NoSolution);
                     }
-                    // `T` -> `dyn Trait` unsizing
-                    (_, &ty::Dynamic(data, region, ty::Dyn)) => {
-                        // Can only unsize to an object-safe type
-                        if data
-                            .principal_def_id()
-                            .is_some_and(|def_id| !tcx.check_is_object_safe(def_id))
-                        {
-                            return Err(NoSolution);
-                        }
-
-                        let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
+
+                    let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
                         return Err(NoSolution);
                     };
-                        // Check that the type implements all of the predicates of the def-id.
-                        // (i.e. the principal, all of the associated types match, and any auto traits)
-                        ecx.add_goals(
-                            data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
-                        );
-                        // The type must be Sized to be unsized.
-                        ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])));
-                        // The type must outlive the lifetime of the `dyn` we're unsizing into.
-                        ecx.add_goal(
-                            goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))),
-                        );
-                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                    }
-                    // `[T; n]` -> `[T]` unsizing
-                    (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
-                        // We just require that the element type stays the same
-                        ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
-                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                    }
-                    // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
-                    (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs))
-                        if a_def.is_struct() && a_def.did() == b_def.did() =>
-                    {
-                        let unsizing_params = tcx.unsizing_params_for_adt(a_def.did());
-                        // We must be unsizing some type parameters. This also implies
-                        // that the struct has a tail field.
-                        if unsizing_params.is_empty() {
-                            return Err(NoSolution);
-                        }
-
-                        let tail_field = a_def
-                            .non_enum_variant()
-                            .fields
-                            .raw
-                            .last()
-                            .expect("expected unsized ADT to have a tail field");
-                        let tail_field_ty = tcx.type_of(tail_field.did);
-
-                        let a_tail_ty = tail_field_ty.subst(tcx, a_substs);
-                        let b_tail_ty = tail_field_ty.subst(tcx, b_substs);
-
-                        // Substitute just the unsizing params from B into A. The type after
-                        // this substitution must be equal to B. This is so we don't unsize
-                        // unrelated type parameters.
-                        let new_a_substs =
-                            tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| {
-                                if unsizing_params.contains(i as u32) { b_substs[i] } else { a }
-                            }));
-                        let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs);
-
-                        // Finally, we require that `TailA: Unsize<TailB>` for the tail field
-                        // types.
-                        ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
-                        ecx.add_goal(goal.with(
-                            tcx,
-                            ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
-                        ));
-                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                    }
-                    // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
-                    (&ty::Tuple(a_tys), &ty::Tuple(b_tys))
-                        if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
-                    {
-                        let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
-                        let b_last_ty = b_tys.last().unwrap();
-
-                        // Substitute just the tail field of B., and require that they're equal.
-                        let unsized_a_ty =
-                            tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied());
-                        ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
-
-                        // Similar to ADTs, require that the rest of the fields are equal.
-                        ecx.add_goal(goal.with(
-                            tcx,
-                            ty::TraitRef::new(
-                                tcx,
-                                goal.predicate.def_id(),
-                                [*a_last_ty, *b_last_ty],
-                            ),
-                        ));
-                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                    // Check that the type implements all of the predicates of the def-id.
+                    // (i.e. the principal, all of the associated types match, and any auto traits)
+                    ecx.add_goals(
+                        data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
+                    );
+                    // The type must be Sized to be unsized.
+                    ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])));
+                    // The type must outlive the lifetime of the `dyn` we're unsizing into.
+                    ecx.add_goal(
+                        goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))),
+                    );
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                }
+                // `[T; n]` -> `[T]` unsizing
+                (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
+                    // We just require that the element type stays the same
+                    ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                }
+                // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
+                (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs))
+                    if a_def.is_struct() && a_def.did() == b_def.did() =>
+                {
+                    let unsizing_params = tcx.unsizing_params_for_adt(a_def.did());
+                    // We must be unsizing some type parameters. This also implies
+                    // that the struct has a tail field.
+                    if unsizing_params.is_empty() {
+                        return Err(NoSolution);
                     }
-                    _ => Err(NoSolution),
+
+                    let tail_field = a_def
+                        .non_enum_variant()
+                        .fields
+                        .raw
+                        .last()
+                        .expect("expected unsized ADT to have a tail field");
+                    let tail_field_ty = tcx.type_of(tail_field.did);
+
+                    let a_tail_ty = tail_field_ty.subst(tcx, a_substs);
+                    let b_tail_ty = tail_field_ty.subst(tcx, b_substs);
+
+                    // Substitute just the unsizing params from B into A. The type after
+                    // this substitution must be equal to B. This is so we don't unsize
+                    // unrelated type parameters.
+                    let new_a_substs =
+                        tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| {
+                            if unsizing_params.contains(i as u32) { b_substs[i] } else { a }
+                        }));
+                    let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs);
+
+                    // Finally, we require that `TailA: Unsize<TailB>` for the tail field
+                    // types.
+                    ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
+                    ecx.add_goal(goal.with(
+                        tcx,
+                        ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
+                    ));
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 }
-            },
-        )
+                // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
+                (&ty::Tuple(a_tys), &ty::Tuple(b_tys))
+                    if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
+                {
+                    let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
+                    let b_last_ty = b_tys.last().unwrap();
+
+                    // Substitute just the tail field of B., and require that they're equal.
+                    let unsized_a_ty =
+                        tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied());
+                    ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
+
+                    // Similar to ADTs, require that the rest of the fields are equal.
+                    ecx.add_goal(goal.with(
+                        tcx,
+                        ty::TraitRef::new(tcx, goal.predicate.def_id(), [*a_last_ty, *b_last_ty]),
+                    ));
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                }
+                _ => Err(NoSolution),
+            }
+        })
     }
 
     fn consider_builtin_dyn_upcast_candidates(
@@ -488,11 +478,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         }
 
         let mut unsize_dyn_to_principal = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
-            ecx.probe(|r| CandidateKind::Candidate {
-                name: "upcast dyn to principle".into(),
-                result: *r,
-            })
-            .enter(|ecx| -> Result<_, NoSolution> {
+            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.
@@ -714,21 +700,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
     ) -> QueryResult<'tcx> {
-        self.probe(|r| CandidateKind::Candidate { name: "constituent tys".into(), result: *r })
-            .enter(|ecx| {
-                ecx.add_goals(
-                    constituent_tys(ecx, goal.predicate.self_ty())?
-                        .into_iter()
-                        .map(|ty| {
-                            goal.with(
-                                ecx.tcx(),
-                                ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)),
-                            )
-                        })
-                        .collect::<Vec<_>>(),
-                );
-                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-            })
+        self.probe_candidate("constituent tys").enter(|ecx| {
+            ecx.add_goals(
+                constituent_tys(ecx, goal.predicate.self_ty())?
+                    .into_iter()
+                    .map(|ty| {
+                        goal.with(
+                            ecx.tcx(),
+                            ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)),
+                        )
+                    })
+                    .collect::<Vec<_>>(),
+            );
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        })
     }
 
     #[instrument(level = "debug", skip(self))]