From a01d3b13eae1a42ed39f02c5bfed58ff7818e1c7 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Thu, 20 Apr 2023 21:02:30 +0000
Subject: [PATCH 1/4] Print ty placeholders pretty

---
 compiler/rustc_middle/src/ty/print/pretty.rs | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index af76cf7cc4e0d..7c90a33609dae 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -738,7 +738,9 @@ pub trait PrettyPrinter<'tcx>:
                 }
             }
             ty::Placeholder(placeholder) => match placeholder.bound.kind {
-                ty::BoundTyKind::Anon => p!(write("Placeholder({:?})", placeholder)),
+                ty::BoundTyKind::Anon => {
+                    self.pretty_print_placeholder_var(placeholder.universe, placeholder.bound.var)?
+                }
                 ty::BoundTyKind::Param(_, name) => p!(write("{}", name)),
             },
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
@@ -1172,6 +1174,18 @@ pub trait PrettyPrinter<'tcx>:
         }
     }
 
+    fn pretty_print_placeholder_var(
+        &mut self,
+        ui: ty::UniverseIndex,
+        var: ty::BoundVar,
+    ) -> Result<(), Self::Error> {
+        if ui == ty::UniverseIndex::ROOT {
+            write!(self, "!{}", var.index())
+        } else {
+            write!(self, "!{}_{}", ui.index(), var.index())
+        }
+    }
+
     fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> {
         None
     }

From 2fadce5390b356f28f689b889fbf01fbd562b32f Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Thu, 20 Apr 2023 21:36:51 +0000
Subject: [PATCH 2/4] Only consider alias bound candidates for types that come
 'from' the param-env

---
 .../src/solve/assembly/mod.rs                 | 65 ++++++++++++++++++-
 .../src/solve/project_goals.rs                | 24 +++++++
 .../src/solve/trait_goals.rs                  | 24 +++++++
 .../traits/new-solver/alias-bound-unsound.rs  | 27 ++++++++
 .../new-solver/alias-bound-unsound.stderr     | 24 +++++++
 5 files changed, 162 insertions(+), 2 deletions(-)
 create mode 100644 tests/ui/traits/new-solver/alias-bound-unsound.rs
 create mode 100644 tests/ui/traits/new-solver/alias-bound-unsound.stderr

diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index bacb0e32efc1a..ac642be4e0ad8 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -8,6 +8,7 @@ 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::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
 use rustc_middle::ty::fast_reject::TreatProjections;
 use rustc_middle::ty::TypeFoldable;
@@ -87,7 +88,9 @@ pub(super) enum CandidateSource {
 }
 
 /// Methods used to assemble candidates for either trait or projection goals.
-pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
+pub(super) trait GoalKind<'tcx>:
+    TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display
+{
     fn self_ty(self) -> Ty<'tcx>;
 
     fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>;
@@ -106,6 +109,12 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
         requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
     ) -> QueryResult<'tcx>;
 
+    fn consider_alias_bound_clause(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        assumption: ty::Predicate<'tcx>,
+    ) -> QueryResult<'tcx>;
+
     // Consider a clause specifically for a `dyn Trait` self type. This requires
     // additionally checking all of the supertraits and object bounds to hold,
     // since they're not implied by the well-formedness of the object type.
@@ -463,7 +472,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
         for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs)
         {
-            match G::consider_implied_clause(self, goal, assumption, []) {
+            match G::consider_alias_bound_clause(self, goal, assumption) {
                 Ok(result) => {
                     candidates.push(Candidate { source: CandidateSource::AliasBound, result })
                 }
@@ -602,4 +611,56 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         }
         self.flounder(&responses)
     }
+
+    #[instrument(level = "debug", skip(self), ret)]
+    pub(super) fn evaluate_alias_bound_self_is_well_formed<G: GoalKind<'tcx>>(
+        &mut self,
+        goal: Goal<'tcx, G>,
+    ) -> QueryResult<'tcx> {
+        match *goal.predicate.self_ty().kind() {
+            ty::Alias(ty::Projection, projection_ty) => {
+                let mut param_env_candidates = vec![];
+                let projection_trait_ref = projection_ty.trait_ref(self.tcx());
+
+                if projection_trait_ref.self_ty().is_ty_var() {
+                    return self
+                        .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
+                }
+
+                let trait_goal = goal.with(
+                    self.tcx(),
+                    ty::TraitPredicate {
+                        trait_ref: projection_trait_ref,
+                        constness: ty::BoundConstness::NotConst,
+                        polarity: ty::ImplPolarity::Positive,
+                    },
+                );
+                self.assemble_param_env_candidates(trait_goal, &mut param_env_candidates);
+
+                // FIXME: Bad bad bad bad bad !!!!!
+                let lang_items = self.tcx().lang_items();
+                let trait_def_id = projection_trait_ref.def_id;
+                let funky_built_in_res = if lang_items.pointee_trait() == Some(trait_def_id) {
+                    G::consider_builtin_pointee_candidate(self, goal)
+                } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
+                    G::consider_builtin_discriminant_kind_candidate(self, goal)
+                } else {
+                    Err(NoSolution)
+                };
+                if let Ok(result) = funky_built_in_res {
+                    param_env_candidates
+                        .push(Candidate { source: CandidateSource::BuiltinImpl, result });
+                }
+
+                self.merge_candidates(param_env_candidates)
+            }
+            ty::Alias(ty::Opaque, _opaque_ty) => match goal.param_env.reveal() {
+                Reveal::UserFacing => {
+                    self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                }
+                Reveal::All => return Err(NoSolution),
+            },
+            _ => bug!("we shouldn't have gotten here!"),
+        }
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 14cb43b89c3aa..5f5b702ad4a81 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -82,6 +82,30 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         }
     }
 
+    fn consider_alias_bound_clause(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        assumption: ty::Predicate<'tcx>,
+    ) -> QueryResult<'tcx> {
+        if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
+            && poly_projection_pred.projection_def_id() == goal.predicate.def_id()
+        {
+            ecx.probe(|ecx| {
+                let assumption_projection_pred =
+                    ecx.instantiate_binder_with_infer(poly_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.evaluate_alias_bound_self_is_well_formed(goal)
+            })
+        } else {
+            Err(NoSolution)
+        }
+    }
+
     fn consider_object_bound_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 1abcc80d01a32..a911a365aa0a1 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -104,6 +104,30 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         }
     }
 
+    fn consider_alias_bound_clause(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        assumption: ty::Predicate<'tcx>,
+    ) -> QueryResult<'tcx> {
+        if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
+            && poly_trait_pred.def_id() == goal.predicate.def_id()
+        {
+            // FIXME: Constness and polarity
+            ecx.probe(|ecx| {
+                let assumption_trait_pred =
+                    ecx.instantiate_binder_with_infer(poly_trait_pred);
+                ecx.eq(
+                    goal.param_env,
+                    goal.predicate.trait_ref,
+                    assumption_trait_pred.trait_ref,
+                )?;
+                ecx.evaluate_alias_bound_self_is_well_formed(goal)
+            })
+        } else {
+            Err(NoSolution)
+        }
+    }
+
     fn consider_object_bound_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.rs b/tests/ui/traits/new-solver/alias-bound-unsound.rs
new file mode 100644
index 0000000000000..00294c708f1fa
--- /dev/null
+++ b/tests/ui/traits/new-solver/alias-bound-unsound.rs
@@ -0,0 +1,27 @@
+// compile-flags: -Ztrait-solver=next
+
+// Makes sure that alias bounds are not unsound!
+
+#![feature(trivial_bounds)]
+
+trait Foo {
+    type Item: Copy
+    where
+        <Self as Foo>::Item: Copy;
+
+    fn copy_me(x: &Self::Item) -> Self::Item {
+        *x
+    }
+}
+
+impl Foo for () {
+    type Item = String where String: Copy;
+}
+
+fn main() {
+    let x = String::from("hello, world");
+    drop(<() as Foo>::copy_me(&x));
+    //~^ ERROR `<() as Foo>::Item: Copy` is not satisfied
+    //~| ERROR `<() as Foo>::Item` is not well-formed
+    println!("{x}");
+}
diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.stderr b/tests/ui/traits/new-solver/alias-bound-unsound.stderr
new file mode 100644
index 0000000000000..9a43d2a6639ce
--- /dev/null
+++ b/tests/ui/traits/new-solver/alias-bound-unsound.stderr
@@ -0,0 +1,24 @@
+error[E0277]: the trait bound `<() as Foo>::Item: Copy` is not satisfied
+  --> $DIR/alias-bound-unsound.rs:23:10
+   |
+LL |     drop(<() as Foo>::copy_me(&x));
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `<() as Foo>::Item`
+   |
+note: required by a bound in `Foo::Item`
+  --> $DIR/alias-bound-unsound.rs:10:30
+   |
+LL |     type Item: Copy
+   |          ---- required by a bound in this associated type
+LL |     where
+LL |         <Self as Foo>::Item: Copy;
+   |                              ^^^^ required by this bound in `Foo::Item`
+
+error: the type `<() as Foo>::Item` is not well-formed
+  --> $DIR/alias-bound-unsound.rs:23:10
+   |
+LL |     drop(<() as Foo>::copy_me(&x));
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.

From b39846f85c3c198428d5bc09b6053dea2a79f59f Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Thu, 20 Apr 2023 22:14:43 +0000
Subject: [PATCH 3/4] Make object bound confirmation simpler in new solver

---
 compiler/rustc_middle/src/ty/mod.rs           |   3 +
 .../src/solve/assembly/mod.rs                 |   9 +-
 .../src/solve/assembly/structural_traits.rs   | 109 +-----------------
 .../src/solve/project_goals.rs                |  10 +-
 .../src/solve/search_graph/mod.rs             |   1 +
 .../src/solve/trait_goals.rs                  |   9 +-
 .../new-solver/higher-ranked-dyn-bounds.rs    |   5 +-
 .../higher-ranked-dyn-bounds.stderr           |  18 +++
 .../new-solver/more-object-bound.stderr       |   4 -
 9 files changed, 41 insertions(+), 127 deletions(-)
 create mode 100644 tests/ui/traits/new-solver/higher-ranked-dyn-bounds.stderr

diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 1061c32079305..e3c82cac36cef 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -522,6 +522,9 @@ impl<'tcx> Predicate<'tcx> {
     #[instrument(level = "debug", skip(tcx), ret)]
     pub fn is_coinductive(self, tcx: TyCtxt<'tcx>) -> bool {
         match self.kind().skip_binder() {
+            // Always coinductive in the new solver.
+            _ if tcx.trait_solver_next() => true,
+
             ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
                 tcx.trait_is_coinductive(data.def_id())
             }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index ac642be4e0ad8..e768189235845 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -115,10 +115,11 @@ pub(super) trait GoalKind<'tcx>:
         assumption: ty::Predicate<'tcx>,
     ) -> QueryResult<'tcx>;
 
-    // Consider a clause specifically for a `dyn Trait` self type. This requires
+    // FIXME: better wording here.
+    // Consider a clause that is spooky and we cannot trust. This requires
     // additionally checking all of the supertraits and object bounds to hold,
-    // since they're not implied by the well-formedness of the object type.
-    fn consider_object_bound_candidate(
+    // since they're not implied by the well-formedness of anything necessarily.
+    fn consider_non_wf_assumption(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Predicate<'tcx>,
@@ -538,7 +539,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                 continue;
             }
 
-            match G::consider_object_bound_candidate(self, goal, assumption) {
+            match G::consider_non_wf_assumption(self, goal, assumption) {
                 Ok(result) => {
                     candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
                 }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 1a566e87dc8e3..f7831dcf68baf 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -1,9 +1,6 @@
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::{def_id::DefId, Movability, Mutability};
+use rustc_hir::{Movability, Mutability};
 use rustc_infer::traits::query::NoSolution;
-use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
-};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 
 use crate::solve::EvalCtxt;
 
@@ -301,51 +298,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
     }
 }
 
-/// Assemble a list of predicates that would be present on a theoretical
-/// user impl for an object type. These predicates must be checked any time
-/// we assemble a built-in object candidate for an object type, since they
-/// are not implied by the well-formedness of the type.
-///
-/// For example, given the following traits:
-///
-/// ```rust,ignore (theoretical code)
-/// trait Foo: Baz {
-///     type Bar: Copy;
-/// }
-///
-/// trait Baz {}
-/// ```
-///
-/// For the dyn type `dyn Foo<Item = Ty>`, we can imagine there being a
-/// pair of theoretical impls:
-///
-/// ```rust,ignore (theoretical code)
-/// impl Foo for dyn Foo<Item = Ty>
-/// where
-///     Self: Baz,
-///     <Self as Foo>::Bar: Copy,
-/// {
-///     type Bar = Ty;
-/// }
-///
-/// impl Baz for dyn Foo<Item = Ty> {}
-/// ```
-///
-/// However, in order to make such impls well-formed, we need to do an
-/// additional step of eagerly folding the associated types in the where
-/// clauses of the impl. In this example, that means replacing
-/// `<Self as Foo>::Bar` with `Ty` in the first impl.
-///
-// FIXME: This is only necessary as `<Self as Trait>::Assoc: ItemBound`
-// bounds in impls are trivially proven using the item bound candidates.
-// This is unsound in general and once that is fixed, we don't need to
-// normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9
-// for more details.
-pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
+/// Assemble a list of predicates that need to hold for a trait implementation
+/// to be WF.
+pub(in crate::solve) fn requirements_for_trait_wf<'tcx>(
     ecx: &EvalCtxt<'_, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
-    object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
 ) -> Vec<ty::Predicate<'tcx>> {
     let tcx = ecx.tcx();
     let mut requirements = vec![];
@@ -359,59 +316,5 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
             requirements.extend(tcx.item_bounds(item.def_id).subst(tcx, trait_ref.substs));
         }
     }
-
-    let mut replace_projection_with = FxHashMap::default();
-    for bound in object_bound {
-        if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() {
-            let proj = proj.with_self_ty(tcx, trait_ref.self_ty());
-            let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj));
-            assert_eq!(
-                old_ty,
-                None,
-                "{} has two substitutions: {} and {}",
-                proj.projection_ty,
-                proj.term,
-                old_ty.unwrap()
-            );
-        }
-    }
-
-    requirements.fold_with(&mut ReplaceProjectionWith {
-        ecx,
-        param_env,
-        mapping: replace_projection_with,
-    })
-}
-
-struct ReplaceProjectionWith<'a, 'tcx> {
-    ecx: &'a EvalCtxt<'a, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
-}
-
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
-        self.ecx.tcx()
-    }
-
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
-            && let Some(replacement) = self.mapping.get(&alias_ty.def_id)
-        {
-            // We may have a case where our object type's projection bound is higher-ranked,
-            // but the where clauses we instantiated are not. We can solve this by instantiating
-            // the binder at the usage site.
-            let proj = self.ecx.instantiate_binder_with_infer(*replacement);
-            // FIXME: Technically this folder could be fallible?
-            let nested = self
-                .ecx
-                .eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty)
-                .expect("expected to be able to unify goal projection with dyn's projection");
-            // FIXME: Technically we could register these too..
-            assert!(nested.is_empty(), "did not expect unification to have any nested goals");
-            proj.term.ty().unwrap()
-        } else {
-            ty.super_fold_with(self)
-        }
-    }
+    requirements
 }
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 5f5b702ad4a81..7b4e9125748f2 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -106,7 +106,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         }
     }
 
-    fn consider_object_bound_candidate(
+    fn consider_non_wf_assumption(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Predicate<'tcx>,
@@ -124,16 +124,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                     goal.predicate.projection_ty,
                     assumption_projection_pred.projection_ty,
                 )?;
-
-                let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
-                    bug!("expected object type in `consider_object_bound_candidate`");
-                };
                 ecx.add_goals(
-                    structural_traits::predicates_for_object_candidate(
+                    structural_traits::requirements_for_trait_wf(
                         &ecx,
-                        goal.param_env,
                         goal.predicate.projection_ty.trait_ref(tcx),
-                        bounds,
                     )
                     .into_iter()
                     .map(|pred| goal.with(tcx, pred)),
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
index 050269fa973e9..c47ffb04ebe35 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -18,6 +18,7 @@ rustc_index::newtype_index! {
     pub struct StackDepth {}
 }
 
+#[derive(Debug)]
 struct StackElem<'tcx> {
     goal: CanonicalGoal<'tcx>,
     has_been_used: bool,
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index a911a365aa0a1..c85e43189447f 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -128,7 +128,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         }
     }
 
-    fn consider_object_bound_candidate(
+    fn consider_non_wf_assumption(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Predicate<'tcx>,
@@ -147,15 +147,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                 )?;
 
                 let tcx = ecx.tcx();
-                let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
-                    bug!("expected object type in `consider_object_bound_candidate`");
-                };
                 ecx.add_goals(
-                    structural_traits::predicates_for_object_candidate(
+                    structural_traits::requirements_for_trait_wf(
                         &ecx,
-                        goal.param_env,
                         goal.predicate.trait_ref,
-                        bounds,
                     )
                     .into_iter()
                     .map(|pred| goal.with(tcx, pred)),
diff --git a/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs
index c886aeeda3e46..5d1a1d0bba794 100644
--- a/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs
+++ b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs
@@ -1,5 +1,8 @@
 // compile-flags: -Ztrait-solver=next
-// check-pass
+// known-bug: unknown
+
+// Remove this when we fix this bug.
+#![recursion_limit = "10"]
 
 trait Trait<'a> {
     type Item: for<'b> Trait2<'b>;
diff --git a/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.stderr b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.stderr
new file mode 100644
index 0000000000000..d2803ccd6ff80
--- /dev/null
+++ b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.stderr
@@ -0,0 +1,18 @@
+error[E0275]: overflow evaluating the requirement `for<'a> dyn for<'a> Trait<'a, for<'a> Item = ()>: Trait<'a>`
+  --> $DIR/higher-ranked-dyn-bounds.rs:17:17
+   |
+LL |     needs_trait(x);
+   |     ----------- ^
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`higher_ranked_dyn_bounds`)
+note: required by a bound in `needs_trait`
+  --> $DIR/higher-ranked-dyn-bounds.rs:14:28
+   |
+LL | fn needs_trait(_: Box<impl for<'a> Trait<'a> + ?Sized>) {}
+   |                            ^^^^^^^^^^^^^^^^^ required by this bound in `needs_trait`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/new-solver/more-object-bound.stderr b/tests/ui/traits/new-solver/more-object-bound.stderr
index 4554b8c7473cb..51a33429f2086 100644
--- a/tests/ui/traits/new-solver/more-object-bound.stderr
+++ b/tests/ui/traits/new-solver/more-object-bound.stderr
@@ -12,10 +12,6 @@ LL | fn foo<A, B, T: ?Sized>(x: T::A) -> B
 LL | where
 LL |     T: Trait<B = B>,
    |        ^^^^^^^^^^^^ required by this bound in `foo`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | fn transmute<A, B>(x: A) -> B where dyn Trait<A = A, B = B>: Trait {
-   |                               ++++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 

From 6da9e7f1c53485c3803f40be644a881d0aea2cdc Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Thu, 20 Apr 2023 23:49:36 +0000
Subject: [PATCH 4/4] Nested alias bounds

---
 .../src/solve/assembly/mod.rs                 |  5 +++++
 .../traits/new-solver/nested-alias-bound.rs   | 20 +++++++++++++++++++
 2 files changed, 25 insertions(+)
 create mode 100644 tests/ui/traits/new-solver/nested-alias-bound.rs

diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index e768189235845..8bcaf37bfd7e6 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -636,7 +636,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                         polarity: ty::ImplPolarity::Positive,
                     },
                 );
+
+                // FIXME: We probably need some sort of recursion depth incr here.
+                // Can't come up with an example yet, though, and the worst case
+                // we can have is a compiler stack overflow...
                 self.assemble_param_env_candidates(trait_goal, &mut param_env_candidates);
+                self.assemble_alias_bound_candidates(trait_goal, &mut param_env_candidates);
 
                 // FIXME: Bad bad bad bad bad !!!!!
                 let lang_items = self.tcx().lang_items();
diff --git a/tests/ui/traits/new-solver/nested-alias-bound.rs b/tests/ui/traits/new-solver/nested-alias-bound.rs
new file mode 100644
index 0000000000000..c365902dbe5e8
--- /dev/null
+++ b/tests/ui/traits/new-solver/nested-alias-bound.rs
@@ -0,0 +1,20 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+trait A {
+    type A: B;
+}
+
+trait B {
+    type B: C;
+}
+
+trait C {}
+
+fn needs_c<T: C>() {}
+
+fn test<T: A>() {
+    needs_c::<<T::A as B>::B>();
+}
+
+fn main() {}