about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs25
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs13
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs13
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs383
4 files changed, 237 insertions, 197 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 6920e790e71..942f4088472 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -94,6 +94,7 @@ pub(super) enum CandidateSource {
 #[derive(Debug, Clone, Copy)]
 pub(super) enum BuiltinImplSource {
     TraitUpcasting,
+    TupleUnsize,
     Object,
     Misc,
     Ambiguity,
@@ -281,20 +282,19 @@ 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.
-    fn consider_builtin_unsize_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        goal: Goal<'tcx, Self>,
-    ) -> QueryResult<'tcx>;
-
+    ///
     /// `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_dyn_upcast_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+    fn consider_builtin_unsize_and_upcast_candidates(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
-    ) -> Vec<CanonicalResponse<'tcx>>;
+    ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)>;
 
     fn consider_builtin_discriminant_kind_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
@@ -610,8 +610,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             G::consider_builtin_future_candidate(self, goal)
         } else if lang_items.gen_trait() == Some(trait_def_id) {
             G::consider_builtin_generator_candidate(self, goal)
-        } else if lang_items.unsize_trait() == Some(trait_def_id) {
-            G::consider_builtin_unsize_candidate(self, goal)
         } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
             G::consider_builtin_discriminant_kind_candidate(self, goal)
         } else if lang_items.destruct_trait() == Some(trait_def_id) {
@@ -633,11 +631,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         // There may be multiple unsize candidates for a trait with several supertraits:
         // `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
         if lang_items.unsize_trait() == Some(trait_def_id) {
-            for result in G::consider_builtin_dyn_upcast_candidates(self, goal) {
-                candidates.push(Candidate {
-                    source: CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting),
-                    result,
-                });
+            for (result, source) in G::consider_builtin_unsize_and_upcast_candidates(self, goal) {
+                candidates.push(Candidate { source: CandidateSource::BuiltinImpl(source), result });
             }
         }
     }
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 e2f91d7668d..cdfbaedb8c2 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -116,10 +116,19 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
                 ),
             ) => rematch_object(self, goal, nested_obligations),
 
-            (Certainty::Maybe(_), CandidateSource::BuiltinImpl(BuiltinImplSource::Misc))
+            (
+                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))
                 if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) =>
             {
-                rematch_unsize(self, goal, nested_obligations)
+                Ok(Some(ImplSource::TupleUnsizing(nested_obligations)))
             }
 
             // Technically some builtin impls have nested obligations, but if
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 222ed9939ba..0f4fec50427 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};
+use super::assembly::{self, structural_traits, BuiltinImplSource};
 use super::EvalCtxt;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -502,17 +502,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         )
     }
 
-    fn consider_builtin_unsize_candidate(
+    fn consider_builtin_unsize_and_upcast_candidates(
         _ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
-    ) -> QueryResult<'tcx> {
-        bug!("`Unsize` does not have an associated type: {:?}", goal);
-    }
-
-    fn consider_builtin_dyn_upcast_candidates(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
-        goal: Goal<'tcx, Self>,
-    ) -> Vec<CanonicalResponse<'tcx>> {
+    ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
         bug!("`Unsize` does not have an associated type: {:?}", goal);
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 69b30f0a1a8..7f813c58c84 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -1,6 +1,6 @@
 //! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
 
-use super::assembly::{self, structural_traits};
+use super::assembly::{self, structural_traits, BuiltinImplSource};
 use super::search_graph::OverflowHandler;
 use super::{EvalCtxt, SolverMode};
 use rustc_hir::def_id::DefId;
@@ -8,7 +8,7 @@ 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, MaybeCause, QueryResult};
+use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
@@ -367,7 +367,59 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         )
     }
 
-    fn consider_builtin_unsize_candidate(
+    fn consider_builtin_unsize_and_upcast_candidates(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return vec![];
+        }
+
+        ecx.probe(|_| CandidateKind::DynUpcastingAssembly).enter(|ecx| {
+            let a_ty = goal.predicate.self_ty();
+            // We need to normalize the b_ty since it's matched structurally
+            // in the other functions below.
+            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)
+                            .unwrap(),
+                        BuiltinImplSource::Ambiguity,
+                    )];
+                }
+                Err(_) => return vec![],
+            };
+
+            let mut results = vec![];
+            results.extend(
+                ecx.consider_builtin_dyn_upcast_candidates(goal.param_env, 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| {
+                        // If we're unsizing from tuple -> tuple, detect
+                        let source =
+                            if matches!((a_ty.kind(), b_ty.kind()), (ty::Tuple(..), ty::Tuple(..)))
+                            {
+                                BuiltinImplSource::TupleUnsize
+                            } else {
+                                BuiltinImplSource::Misc
+                            };
+                        (resp, source)
+                    },
+                ),
+            );
+
+            results
+        })
+    }
+
+    fn consider_builtin_discriminant_kind_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
@@ -375,20 +427,72 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             return Err(NoSolution);
         }
 
-        let tcx = ecx.tcx();
-        let a_ty = goal.predicate.self_ty();
-        let b_ty = goal.predicate.trait_ref.args.type_at(1);
+        // `DiscriminantKind` is automatically implemented for every type.
+        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+    }
 
-        ecx.probe_candidate("builtin unsize").enter(|ecx| {
-            let Some(b_ty) = ecx.normalize_non_self_ty(b_ty, goal.param_env)? else {
-                return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
-                    MaybeCause::Overflow,
-                ));
-            };
+    fn consider_builtin_destruct_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
+        if !goal.param_env.is_const() {
+            // `Destruct` is automatically implemented for every type in
+            // non-const environments.
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        } else {
+            // FIXME(-Ztrait-solver=next): Implement this when we get const working in the new solver
+            Err(NoSolution)
+        }
+    }
+
+    fn consider_builtin_transmute_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
+        // `rustc_transmute` does not have support for type or const params
+        if goal.has_non_region_placeholders() {
+            return Err(NoSolution);
+        }
+
+        // Erase regions because we compute layouts in `rustc_transmute`,
+        // which will ICE for region vars.
+        let args = ecx.tcx().erase_regions(goal.predicate.trait_ref.args);
+
+        let Some(assume) =
+            rustc_transmute::Assume::from_const(ecx.tcx(), goal.param_env, args.const_at(3))
+        else {
+            return Err(NoSolution);
+        };
 
+        let certainty = ecx.is_transmutable(
+            rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) },
+            args.type_at(2),
+            assume,
+        )?;
+        ecx.evaluate_added_goals_and_make_canonical_response(certainty)
+    }
+}
+
+impl<'tcx> EvalCtxt<'_, 'tcx> {
+    fn consider_builtin_unsize_candidate(
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        a_ty: Ty<'tcx>,
+        b_ty: Ty<'tcx>,
+    ) -> QueryResult<'tcx> {
+        self.probe_candidate("builtin unsize").enter(|ecx| {
+            let tcx = ecx.tcx();
             match (a_ty.kind(), b_ty.kind()) {
-                (_, ty::Infer(ty::TyVar(_))) => {
-                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+                (ty::Infer(ty::TyVar(_)), _) | (_, ty::Infer(ty::TyVar(_))) => {
+                    bug!("unexpected type variable in unsize goal")
                 }
                 // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`
                 (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => {
@@ -413,20 +517,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                     // 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))),
+                        data.iter()
+                            .map(|pred| Goal::new(tcx, param_env, 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])));
+                    ecx.add_goal(Goal::new(
+                        tcx,
+                        param_env,
+                        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.add_goal(Goal::new(
+                        tcx,
+                        param_env,
+                        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.eq(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>`
@@ -457,10 +568,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
 
                     // 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(
+                    ecx.eq(param_env, unsized_a_ty, b_ty)?;
+                    ecx.add_goal(Goal::new(
                         tcx,
-                        ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
+                        param_env,
+                        ty::TraitRef::new(
+                            tcx,
+                            tcx.lang_items().unsize_trait().unwrap(),
+                            [a_tail_ty, b_tail_ty],
+                        ),
                     ));
                     ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 }
@@ -474,12 +590,17 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                     // Substitute just the tail field of B., and require that they're equal.
                     let unsized_a_ty =
                         Ty::new_tup_from_iter(tcx, a_rest_tys.iter().chain([b_last_ty]).copied());
-                    ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
+                    ecx.eq(param_env, unsized_a_ty, b_ty)?;
 
                     // Similar to ADTs, require that the rest of the fields are equal.
-                    ecx.add_goal(goal.with(
+                    ecx.add_goal(Goal::new(
                         tcx,
-                        ty::TraitRef::new(tcx, goal.predicate.def_id(), [*a_last_ty, *b_last_ty]),
+                        param_env,
+                        ty::TraitRef::new(
+                            tcx,
+                            tcx.lang_items().unsize_trait().unwrap(),
+                            [*a_last_ty, *b_last_ty],
+                        ),
                     ));
                     ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 }
@@ -489,164 +610,86 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_dyn_upcast_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        goal: Goal<'tcx, Self>,
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        a_ty: Ty<'tcx>,
+        b_ty: Ty<'tcx>,
     ) -> Vec<CanonicalResponse<'tcx>> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
-            return vec![];
+        if a_ty.is_ty_var() || b_ty.is_ty_var() {
+            bug!("unexpected type variable in unsize goal")
         }
 
-        let tcx = ecx.tcx();
-
-        // Need to wrap in a probe since `normalize_non_self_ty` has side-effects.
-        ecx.probe(|_| CandidateKind::DynUpcastingAssembly).enter(|ecx| {
-            let a_ty = goal.predicate.self_ty();
-            let b_ty = goal.predicate.trait_ref.args.type_at(1);
-            let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else {
-                return vec![];
-            };
+        let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else {
+            return vec![];
+        };
+        let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else {
+            return vec![];
+        };
 
-            // We don't care about `ty::Infer` here or errors here, since we'll
-            // register an ambiguous/error response in the other unsize candidate
-            // assembly function.
-            let Ok(Some(b_ty)) = ecx.normalize_non_self_ty(b_ty, goal.param_env) else {
-                return vec![];
-            };
-            let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else {
-                return vec![];
-            };
+        let tcx = self.tcx();
+        // All of a's auto traits need to be in b's auto traits.
+        let auto_traits_compatible =
+            b_data.auto_traits().all(|b| a_data.auto_traits().any(|a| a == b));
+        if !auto_traits_compatible {
+            return vec![];
+        }
 
-            // All of a's auto traits need to be in b's auto traits.
-            let auto_traits_compatible =
-                b_data.auto_traits().all(|b| a_data.auto_traits().any(|a| a == b));
-            if !auto_traits_compatible {
-                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);
 
-            let mut unsize_dyn_to_principal = |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(goal.param_env, new_a_ty, b_ty)?;
-                        ecx.add_goal(goal.with(
-                            tcx,
-                            ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
-                        ));
-                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                    },
-                )
-            };
+                // 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);
+        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;
                 }
-            } 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);
-                    }
+                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);
                 }
             }
-
-            responses
-        })
-    }
-
-    fn consider_builtin_discriminant_kind_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        goal: Goal<'tcx, Self>,
-    ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
-            return Err(NoSolution);
-        }
-
-        // `DiscriminantKind` is automatically implemented for every type.
-        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-    }
-
-    fn consider_builtin_destruct_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        goal: Goal<'tcx, Self>,
-    ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
-            return Err(NoSolution);
         }
 
-        if !goal.param_env.is_const() {
-            // `Destruct` is automatically implemented for every type in
-            // non-const environments.
-            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-        } else {
-            // FIXME(-Ztrait-solver=next): Implement this when we get const working in the new solver
-            Err(NoSolution)
-        }
+        responses
     }
 
-    fn consider_builtin_transmute_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        goal: Goal<'tcx, Self>,
-    ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
-            return Err(NoSolution);
-        }
-
-        // `rustc_transmute` does not have support for type or const params
-        if goal.has_non_region_placeholders() {
-            return Err(NoSolution);
-        }
-
-        // Erase regions because we compute layouts in `rustc_transmute`,
-        // which will ICE for region vars.
-        let args = ecx.tcx().erase_regions(goal.predicate.trait_ref.args);
-
-        let Some(assume) =
-            rustc_transmute::Assume::from_const(ecx.tcx(), goal.param_env, args.const_at(3))
-        else {
-            return Err(NoSolution);
-        };
-
-        let certainty = ecx.is_transmutable(
-            rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) },
-            args.type_at(2),
-            assume,
-        )?;
-        ecx.evaluate_added_goals_and_make_canonical_response(certainty)
-    }
-}
-
-impl<'tcx> EvalCtxt<'_, 'tcx> {
     // Return `Some` if there is an impl (built-in or user provided) that may
     // hold for the self type of the goal, which for coherence and soundness
     // purposes must disqualify the built-in auto impl assembled by considering