From b84b1da2dbacdfd7e33428540062380b56bfd8de Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 17 Jan 2023 19:29:52 +0000
Subject: [PATCH 1/7] Canonicalize trait solver response inside probe

---
 .../src/solve/assembly.rs                     | 22 +++++++------------
 .../rustc_trait_selection/src/solve/mod.rs    |  7 ++++++
 .../src/solve/project_goals.rs                | 10 ++++-----
 .../src/solve/trait_goals.rs                  | 10 ++++-----
 4 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index cd6e4d2bccd5c..c8611294449e9 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -1,7 +1,7 @@
 //! Code shared by trait and projection goals for candidate assembly.
 
 use super::infcx_ext::InferCtxtExt;
-use super::{CanonicalResponse, Certainty, EvalCtxt, Goal};
+use super::{CanonicalResponse, EvalCtxt, Goal, QueryResult};
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::ty::TypeFoldable;
@@ -89,18 +89,18 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
         impl_def_id: DefId,
-    ) -> Result<Certainty, NoSolution>;
+    ) -> QueryResult<'tcx>;
 
     fn consider_builtin_sized_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
-    ) -> Result<Certainty, NoSolution>;
+    ) -> QueryResult<'tcx>;
 
     fn consider_assumption(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Predicate<'tcx>,
-    ) -> Result<Certainty, NoSolution>;
+    ) -> QueryResult<'tcx>;
 }
 impl<'tcx> EvalCtxt<'_, 'tcx> {
     pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
@@ -180,9 +180,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         tcx.for_each_relevant_impl(
             goal.predicate.trait_def_id(tcx),
             goal.predicate.self_ty(),
-            |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id)
-                .and_then(|certainty| self.make_canonical_response(certainty))
-            {
+            |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) {
                 Ok(result) => candidates
                     .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
                 Err(NoSolution) => (),
@@ -203,7 +201,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             Err(NoSolution)
         };
 
-        match result.and_then(|certainty| self.make_canonical_response(certainty)) {
+        match result {
             Ok(result) => {
                 candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
             }
@@ -217,9 +215,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
         for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
-            match G::consider_assumption(self, goal, assumption)
-                .and_then(|certainty| self.make_canonical_response(certainty))
-            {
+            match G::consider_assumption(self, goal, assumption) {
                 Ok(result) => {
                     candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
                 }
@@ -268,9 +264,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             .subst_iter_copied(self.tcx(), alias_ty.substs)
             .enumerate()
         {
-            match G::consider_assumption(self, goal, assumption)
-                .and_then(|certainty| self.make_canonical_response(certainty))
-            {
+            match G::consider_assumption(self, goal, assumption) {
                 Ok(result) => {
                     candidates.push(Candidate { source: CandidateSource::AliasBound(i), result })
                 }
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 579cd6a2d59cd..32eb84635b536 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -313,6 +313,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             }
         })
     }
+
+    fn evaluate_all_and_make_canonical_response(
+        &mut self,
+        goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
+    ) -> QueryResult<'tcx> {
+        self.evaluate_all(goals).and_then(|certainty| self.make_canonical_response(certainty))
+    }
 }
 
 #[instrument(level = "debug", skip(infcx), ret)]
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 0658836fb9cd3..1d85d31705ad4 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -191,7 +191,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
         impl_def_id: DefId,
-    ) -> Result<Certainty, NoSolution> {
+    ) -> QueryResult<'tcx> {
         let tcx = ecx.tcx();
 
         let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
@@ -229,7 +229,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                 impl_def_id
             )? else {
                 let certainty = Certainty::Maybe(MaybeCause::Ambiguity);
-                return Ok(trait_ref_certainty.unify_and(certainty));
+                return ecx.make_canonical_response(trait_ref_certainty.unify_and(certainty));
             };
 
             if !assoc_def.item.defaultness(tcx).has_value() {
@@ -286,14 +286,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
             let rhs_certainty =
                 ecx.evaluate_all(nested_goals).expect("failed to unify with unconstrained term");
 
-            Ok(trait_ref_certainty.unify_and(rhs_certainty))
+            ecx.make_canonical_response(trait_ref_certainty.unify_and(rhs_certainty))
         })
     }
 
     fn consider_builtin_sized_candidate(
         _ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
-    ) -> Result<Certainty, NoSolution> {
+    ) -> QueryResult<'tcx> {
         bug!("`Sized` does not have an associated type: {:?}", goal);
     }
 
@@ -301,7 +301,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         _ecx: &mut EvalCtxt<'_, 'tcx>,
         _goal: Goal<'tcx, Self>,
         assumption: ty::Predicate<'tcx>,
-    ) -> Result<Certainty, NoSolution> {
+    ) -> QueryResult<'tcx> {
         if let Some(_poly_projection_pred) = assumption.to_opt_poly_projection_pred() {
             unimplemented!()
         } else {
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index bbe175d5cc853..111758c77d99c 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -4,7 +4,7 @@ use std::iter;
 
 use super::assembly::{self, Candidate, CandidateSource};
 use super::infcx_ext::InferCtxtExt;
-use super::{Certainty, EvalCtxt, Goal, QueryResult};
+use super::{EvalCtxt, Goal, QueryResult};
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
@@ -29,7 +29,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         impl_def_id: DefId,
-    ) -> Result<Certainty, NoSolution> {
+    ) -> QueryResult<'tcx> {
         let tcx = ecx.tcx();
 
         let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
@@ -53,14 +53,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                 .into_iter()
                 .map(|pred| goal.with(tcx, pred));
             nested_goals.extend(where_clause_bounds);
-            ecx.evaluate_all(nested_goals)
+            ecx.evaluate_all_and_make_canonical_response(nested_goals)
         })
     }
 
     fn consider_builtin_sized_candidate(
         _ecx: &mut EvalCtxt<'_, 'tcx>,
         _goal: Goal<'tcx, Self>,
-    ) -> Result<Certainty, NoSolution> {
+    ) -> QueryResult<'tcx> {
         unimplemented!();
     }
 
@@ -68,7 +68,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         _ecx: &mut EvalCtxt<'_, 'tcx>,
         _goal: Goal<'tcx, Self>,
         assumption: ty::Predicate<'tcx>,
-    ) -> Result<Certainty, NoSolution> {
+    ) -> QueryResult<'tcx> {
         if let Some(_poly_trait_pred) = assumption.to_opt_poly_trait_pred() {
             unimplemented!()
         } else {

From f99b273d577914ee0c9073e2e6144aee17354717 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 17 Jan 2023 19:50:50 +0000
Subject: [PATCH 2/7] implement consider_assumption

---
 .../src/solve/infcx_ext.rs                    | 26 ++++++++++++++
 .../src/solve/project_goals.rs                | 35 ++++++++++++++++---
 .../src/solve/trait_goals.rs                  | 19 +++++++---
 3 files changed, 70 insertions(+), 10 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs
index 9b7feb5053787..47e6c93016a0e 100644
--- a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs
+++ b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs
@@ -25,6 +25,13 @@ pub(super) trait InferCtxtExt<'tcx> {
         lhs: T,
         rhs: T,
     ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>;
+
+    fn sup<T: ToTrace<'tcx>>(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        lhs: T,
+        rhs: T,
+    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>;
 }
 
 impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
@@ -59,4 +66,23 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
                 NoSolution
             })
     }
+
+    #[instrument(level = "debug", skip(self, param_env), ret)]
+    fn sup<T: ToTrace<'tcx>>(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        lhs: T,
+        rhs: T,
+    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
+        self.at(&ObligationCause::dummy(), param_env)
+            .define_opaque_types(false)
+            .sup(lhs, rhs)
+            .map(|InferOk { value: (), obligations }| {
+                obligations.into_iter().map(|o| o.into()).collect()
+            })
+            .map_err(|e| {
+                debug!(?e, "failed to sup");
+                NoSolution
+            })
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 1d85d31705ad4..9ebcb4e4657d8 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -6,7 +6,7 @@ use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::InferCtxt;
+use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime};
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::specialization_graph::LeafDef;
 use rustc_infer::traits::Reveal;
@@ -298,12 +298,37 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
     }
 
     fn consider_assumption(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
-        _goal: Goal<'tcx, Self>,
+        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() {
-            unimplemented!()
+        if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() {
+            ecx.infcx.probe(|_| {
+                let assumption_projection_pred = ecx.infcx.replace_bound_vars_with_fresh_vars(
+                    DUMMY_SP,
+                    LateBoundRegionConversionTime::HigherRankedType,
+                    poly_projection_pred,
+                );
+                let nested_goals = ecx.infcx.sup(
+                    goal.param_env,
+                    goal.predicate.projection_ty,
+                    assumption_projection_pred.projection_ty,
+                )?;
+                let subst_certainty = ecx.evaluate_all(nested_goals)?;
+
+                // The term of our goal should be fully unconstrained, so this should never fail.
+                //
+                // It can however be ambiguous when the resolved type is a projection.
+                let nested_goals = ecx
+                    .infcx
+                    .eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
+                    .expect("failed to unify with unconstrained term");
+                let rhs_certainty = ecx
+                    .evaluate_all(nested_goals)
+                    .expect("failed to unify with unconstrained term");
+
+                ecx.make_canonical_response(subst_certainty.unify_and(rhs_certainty))
+            })
         } else {
             Err(NoSolution)
         }
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 111758c77d99c..362424b0d1431 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -6,10 +6,11 @@ use super::assembly::{self, Candidate, CandidateSource};
 use super::infcx_ext::InferCtxtExt;
 use super::{EvalCtxt, Goal, QueryResult};
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
-use rustc_middle::ty::TraitPredicate;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{ToPolyTraitRef, TraitPredicate};
 use rustc_span::DUMMY_SP;
 
 impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
@@ -65,12 +66,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_assumption(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
-        _goal: Goal<'tcx, Self>,
+        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() {
-            unimplemented!()
+        if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() {
+            // FIXME: Constness and polarity
+            ecx.infcx.probe(|_| {
+                let nested_goals = ecx.infcx.sup(
+                    goal.param_env,
+                    ty::Binder::dummy(goal.predicate.trait_ref),
+                    poly_trait_pred.to_poly_trait_ref(),
+                )?;
+                ecx.evaluate_all_and_make_canonical_response(nested_goals)
+            })
         } else {
             Err(NoSolution)
         }

From 3d87a8e84850e2f5edc0f87ab2f4d3c2b67a48ac Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 17 Jan 2023 18:19:11 +0000
Subject: [PATCH 3/7] Assemble object bound candidates

---
 .../src/solve/assembly.rs                     | 52 +++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index c8611294449e9..0a82c14e226fd 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -4,6 +4,7 @@ use super::infcx_ext::InferCtxtExt;
 use super::{CanonicalResponse, EvalCtxt, Goal, QueryResult};
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
+use rustc_infer::traits::util::elaborate_predicates;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use std::fmt::Debug;
@@ -119,6 +120,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
         self.assemble_alias_bound_candidates(goal, &mut candidates);
 
+        self.assemble_object_bound_candidates(goal, &mut candidates);
+
         candidates
     }
 
@@ -272,4 +275,53 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             }
         }
     }
+
+    fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
+        &mut self,
+        goal: Goal<'tcx, G>,
+        candidates: &mut Vec<Candidate<'tcx>>,
+    ) {
+        let self_ty = goal.predicate.self_ty();
+        let bounds = match *self_ty.kind() {
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Adt(_, _)
+            | ty::Foreign(_)
+            | ty::Str
+            | ty::Array(_, _)
+            | ty::Slice(_)
+            | ty::RawPtr(_)
+            | ty::Ref(_, _, _)
+            | ty::FnDef(_, _)
+            | ty::FnPtr(_)
+            | ty::Alias(..)
+            | ty::Closure(..)
+            | ty::Generator(..)
+            | ty::GeneratorWitness(_)
+            | ty::Never
+            | ty::Tuple(_)
+            | ty::Param(_)
+            | ty::Placeholder(..)
+            | ty::Infer(_)
+            | ty::Error(_) => return,
+            ty::Bound(..) => bug!("unexpected bound type: {goal:?}"),
+            ty::Dynamic(bounds, ..) => bounds,
+        };
+
+        let tcx = self.tcx();
+        for assumption in
+            elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)))
+        {
+            match G::consider_assumption(self, goal, assumption.predicate)
+            {
+                Ok(result) => {
+                    candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
+                }
+                Err(NoSolution) => (),
+            }
+        }
+    }
 }

From 45aa5c0f90124e926662f2c2c2d9efca065e0397 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 17 Jan 2023 20:16:30 +0000
Subject: [PATCH 4/7] Auto and alias traits

---
 compiler/rustc_middle/src/ty/mod.rs           |   5 +
 .../src/solve/assembly.rs                     |  25 +++-
 .../src/solve/project_goals.rs                |  28 +++-
 .../src/solve/trait_goals.rs                  | 132 ++++++++++++++++--
 4 files changed, 169 insertions(+), 21 deletions(-)

diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index e68f27cc0fd5d..db7dd2e5e75d7 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2382,6 +2382,11 @@ impl<'tcx> TyCtxt<'tcx> {
         self.trait_def(trait_def_id).has_auto_impl
     }
 
+    /// Returns `true` if this is a trait alias.
+    pub fn trait_is_alias(self, trait_def_id: DefId) -> bool {
+        self.def_kind(trait_def_id) == DefKind::TraitAlias
+    }
+
     pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool {
         self.trait_is_auto(trait_def_id) || self.lang_items().sized_trait() == Some(trait_def_id)
     }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index 0a82c14e226fd..0759c42338249 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -92,15 +92,25 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy {
         impl_def_id: DefId,
     ) -> QueryResult<'tcx>;
 
-    fn consider_builtin_sized_candidate(
+    fn consider_assumption(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
+        assumption: ty::Predicate<'tcx>,
     ) -> QueryResult<'tcx>;
 
-    fn consider_assumption(
+    fn consider_auto_trait_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
+    fn consider_trait_alias_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
+    fn consider_builtin_sized_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
-        assumption: ty::Predicate<'tcx>,
     ) -> QueryResult<'tcx>;
 }
 impl<'tcx> EvalCtxt<'_, 'tcx> {
@@ -198,7 +208,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     ) {
         let lang_items = self.tcx().lang_items();
         let trait_def_id = goal.predicate.trait_def_id(self.tcx());
-        let result = if lang_items.sized_trait() == Some(trait_def_id) {
+        let result = if self.tcx().trait_is_auto(trait_def_id) {
+            G::consider_auto_trait_candidate(self, goal)
+        } else if self.tcx().trait_is_alias(trait_def_id) {
+            G::consider_trait_alias_candidate(self, goal)
+        } else if lang_items.sized_trait() == Some(trait_def_id) {
             G::consider_builtin_sized_candidate(self, goal)
         } else {
             Err(NoSolution)
@@ -315,8 +329,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         for assumption in
             elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)))
         {
-            match G::consider_assumption(self, goal, assumption.predicate)
-            {
+            match G::consider_assumption(self, goal, assumption.predicate) {
                 Ok(result) => {
                     candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
                 }
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 9ebcb4e4657d8..3c74de09802d5 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -290,13 +290,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         })
     }
 
-    fn consider_builtin_sized_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
-        goal: Goal<'tcx, Self>,
-    ) -> QueryResult<'tcx> {
-        bug!("`Sized` does not have an associated type: {:?}", goal);
-    }
-
     fn consider_assumption(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -333,6 +326,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
             Err(NoSolution)
         }
     }
+
+    fn consider_auto_trait_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        bug!("auto traits do not have associated types: {:?}", goal);
+    }
+
+    fn consider_trait_alias_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        bug!("trait aliases do not have associated types: {:?}", goal);
+    }
+
+    fn consider_builtin_sized_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        bug!("`Sized` does not have an associated type: {:?}", goal);
+    }
 }
 
 /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 362424b0d1431..1f18de2e7a9e0 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -6,7 +6,7 @@ use super::assembly::{self, Candidate, CandidateSource};
 use super::infcx_ext::InferCtxtExt;
 use super::{EvalCtxt, Goal, QueryResult};
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::LateBoundRegionConversionTime;
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -58,13 +58,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         })
     }
 
-    fn consider_builtin_sized_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
-        _goal: Goal<'tcx, Self>,
-    ) -> QueryResult<'tcx> {
-        unimplemented!();
-    }
-
     fn consider_assumption(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -84,9 +77,61 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             Err(NoSolution)
         }
     }
+
+    fn consider_auto_trait_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        ecx.infcx.probe(|_| {
+            let constituent_tys =
+                instantiate_constituent_tys_for_auto_trait(ecx.infcx, goal.predicate.self_ty())?;
+            ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys)
+        })
+    }
+
+    fn consider_trait_alias_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let tcx = ecx.tcx();
+
+        ecx.infcx.probe(|_| {
+            let nested_obligations = tcx
+                .predicates_of(goal.predicate.def_id())
+                .instantiate(tcx, goal.predicate.trait_ref.substs);
+            ecx.evaluate_all_and_make_canonical_response(
+                nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)).collect(),
+            )
+        })
+    }
+
+    fn consider_builtin_sized_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        unimplemented!();
+    }
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
+    fn evaluate_goal_for_constituent_tys_and_make_canonical_response(
+        &mut self,
+        goal: Goal<'tcx, TraitPredicate<'tcx>>,
+        constituent_tys: Vec<Ty<'tcx>>,
+    ) -> QueryResult<'tcx> {
+        self.evaluate_all_and_make_canonical_response(
+            constituent_tys
+                .into_iter()
+                .map(|ty| {
+                    goal.with(
+                        self.tcx(),
+                        ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)),
+                    )
+                })
+                .collect(),
+        )
+    }
+
     pub(super) fn compute_trait_goal(
         &mut self,
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
@@ -162,3 +207,74 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         candidate
     }
 }
+
+// Calculates the constituent types of a type for `auto trait` purposes.
+//
+// For types with an "existential" binder, i.e. generator witnesses, we also
+// instantiate the binder with placeholders eagerly.
+fn instantiate_constituent_tys_for_auto_trait<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Result<Vec<Ty<'tcx>>, NoSolution> {
+    let tcx = infcx.tcx;
+    match *ty.kind() {
+        ty::Uint(_)
+        | ty::Int(_)
+        | ty::Bool
+        | ty::Float(_)
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::Str
+        | ty::Error(_)
+        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+        | ty::Never
+        | ty::Char => Ok(vec![]),
+
+        ty::Placeholder(..)
+        | ty::Dynamic(..)
+        | ty::Param(..)
+        | ty::Foreign(..)
+        | ty::Alias(ty::Projection, ..)
+        | ty::Bound(..)
+        | ty::Infer(ty::TyVar(_)) => {
+            // FIXME: Do we need to mark anything as ambiguous here? Yeah?
+            Err(NoSolution)
+        }
+
+        ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
+
+        ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
+            Ok(vec![element_ty])
+        }
+
+        ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]),
+
+        ty::Tuple(ref tys) => {
+            // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
+            Ok(tys.iter().collect())
+        }
+
+        ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
+
+        ty::Generator(_, ref substs, _) => {
+            let generator_substs = substs.as_generator();
+            Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()])
+        }
+
+        ty::GeneratorWitness(types) => {
+            Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
+        }
+
+        // For `PhantomData<T>`, we pass `T`.
+        ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]),
+
+        ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()),
+
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
+            // We can resolve the `impl Trait` to its concrete type,
+            // which enforces a DAG between the functions requiring
+            // the auto trait bounds in question.
+            Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)])
+        }
+    }
+}

From 685c32fd858acf107108abd6d35782532a0064e2 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 17 Jan 2023 20:24:58 +0000
Subject: [PATCH 5/7] Sized, Copy/Clone

---
 .../src/solve/assembly.rs                     |  10 ++
 .../src/solve/project_goals.rs                |   7 +
 .../src/solve/trait_goals.rs                  | 137 +++++++++++++++++-
 3 files changed, 151 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index 0759c42338249..2336fb53aec28 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -112,7 +112,13 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
+
+    fn consider_builtin_copy_clone_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
 }
+
 impl<'tcx> EvalCtxt<'_, 'tcx> {
     pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
         &mut self,
@@ -214,6 +220,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             G::consider_trait_alias_candidate(self, goal)
         } else if lang_items.sized_trait() == Some(trait_def_id) {
             G::consider_builtin_sized_candidate(self, goal)
+        } else if lang_items.copy_trait() == Some(trait_def_id)
+            || lang_items.clone_trait() == Some(trait_def_id)
+        {
+            G::consider_builtin_copy_clone_candidate(self, goal)
         } else {
             Err(NoSolution)
         };
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 3c74de09802d5..5c1f3f02e93a8 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -347,6 +347,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
     ) -> QueryResult<'tcx> {
         bug!("`Sized` does not have an associated type: {:?}", goal);
     }
+
+    fn consider_builtin_copy_clone_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
+    }
 }
 
 /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 1f18de2e7a9e0..4d94265dc07f5 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -6,6 +6,7 @@ use super::assembly::{self, Candidate, CandidateSource};
 use super::infcx_ext::InferCtxtExt;
 use super::{EvalCtxt, Goal, QueryResult};
 use rustc_hir::def_id::DefId;
+use rustc_hir::{Movability, Mutability};
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
@@ -106,10 +107,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_sized_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
-        _goal: Goal<'tcx, Self>,
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        unimplemented!();
+        ecx.infcx.probe(|_| {
+            let constituent_tys =
+                instantiate_constituent_tys_for_sized_trait(ecx.infcx, goal.predicate.self_ty())?;
+            ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys)
+        })
+    }
+
+    fn consider_builtin_copy_clone_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        ecx.infcx.probe(|_| {
+            let constituent_tys = instantiate_constituent_tys_for_copy_clone_trait(
+                ecx.infcx,
+                goal.predicate.self_ty(),
+            )?;
+            ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys)
+        })
     }
 }
 
@@ -278,3 +296,116 @@ fn instantiate_constituent_tys_for_auto_trait<'tcx>(
         }
     }
 }
+
+fn instantiate_constituent_tys_for_sized_trait<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Result<Vec<Ty<'tcx>>, NoSolution> {
+    match *ty.kind() {
+        ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+        | ty::Uint(_)
+        | ty::Int(_)
+        | ty::Bool
+        | ty::Float(_)
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::RawPtr(..)
+        | ty::Char
+        | ty::Ref(..)
+        | ty::Generator(..)
+        | ty::GeneratorWitness(..)
+        | ty::Array(..)
+        | ty::Closure(..)
+        | ty::Never
+        | ty::Dynamic(_, _, ty::DynStar)
+        | ty::Error(_) => Ok(vec![]),
+
+        ty::Str
+        | ty::Slice(_)
+        | ty::Dynamic(..)
+        | ty::Foreign(..)
+        | ty::Alias(..)
+        | ty::Param(_) => Err(NoSolution),
+
+        ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
+
+        ty::Placeholder(..)
+        | ty::Bound(..)
+        | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
+
+        ty::Tuple(tys) => Ok(tys.to_vec()),
+
+        ty::Adt(def, substs) => {
+            let sized_crit = def.sized_constraint(infcx.tcx);
+            Ok(sized_crit
+                .0
+                .iter()
+                .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs))
+                .collect())
+        }
+    }
+}
+
+fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Result<Vec<Ty<'tcx>>, NoSolution> {
+    match *ty.kind() {
+        ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::Error(_) => Ok(vec![]),
+
+        // Implementations are provided in core
+        ty::Uint(_)
+        | ty::Int(_)
+        | ty::Bool
+        | ty::Float(_)
+        | ty::Char
+        | ty::RawPtr(..)
+        | ty::Never
+        | ty::Ref(_, _, Mutability::Not)
+        | ty::Array(..) => Err(NoSolution),
+
+        ty::Dynamic(..)
+        | ty::Str
+        | ty::Slice(_)
+        | ty::Generator(_, _, Movability::Static)
+        | ty::Foreign(..)
+        | ty::Ref(_, _, Mutability::Mut)
+        | ty::Adt(_, _)
+        | ty::Alias(_, _)
+        | ty::Param(_) => Err(NoSolution),
+
+        ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
+
+        ty::Placeholder(..)
+        | ty::Bound(..)
+        | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
+
+        ty::Tuple(tys) => Ok(tys.to_vec()),
+
+        ty::Closure(_, substs) => match *substs.as_closure().tupled_upvars_ty().kind() {
+            ty::Tuple(tys) => Ok(tys.to_vec()),
+            ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
+            _ => bug!(),
+        },
+
+        ty::Generator(_, substs, Movability::Movable) => {
+            if infcx.tcx.features().generator_clone {
+                let generator = substs.as_generator();
+                match *generator.tupled_upvars_ty().kind() {
+                    ty::Tuple(tys) => Ok(tys.iter().chain([generator.witness()]).collect()),
+                    ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
+                    _ => bug!(),
+                }
+            } else {
+                Err(NoSolution)
+            }
+        }
+
+        ty::GeneratorWitness(types) => {
+            Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
+        }
+    }
+}

From 34127c50803cc0a3c68f1f15480399e19d3813af Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Wed, 18 Jan 2023 14:40:16 +0000
Subject: [PATCH 6/7] no subtyping in the new trait solver

---
 .../src/solve/infcx_ext.rs                    | 36 +++++++------------
 .../src/solve/project_goals.rs                | 11 +++---
 .../src/solve/trait_goals.rs                  | 10 +++---
 3 files changed, 23 insertions(+), 34 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs
index 47e6c93016a0e..42f597c781d25 100644
--- a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs
+++ b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs
@@ -1,10 +1,10 @@
 use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TypeFoldable};
 use rustc_span::DUMMY_SP;
 
 use super::Goal;
@@ -26,12 +26,10 @@ pub(super) trait InferCtxtExt<'tcx> {
         rhs: T,
     ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>;
 
-    fn sup<T: ToTrace<'tcx>>(
+    fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>(
         &self,
-        param_env: ty::ParamEnv<'tcx>,
-        lhs: T,
-        rhs: T,
-    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>;
+        value: ty::Binder<'tcx, T>,
+    ) -> T;
 }
 
 impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
@@ -67,22 +65,14 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
             })
     }
 
-    #[instrument(level = "debug", skip(self, param_env), ret)]
-    fn sup<T: ToTrace<'tcx>>(
+    fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>(
         &self,
-        param_env: ty::ParamEnv<'tcx>,
-        lhs: T,
-        rhs: T,
-    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
-        self.at(&ObligationCause::dummy(), param_env)
-            .define_opaque_types(false)
-            .sup(lhs, rhs)
-            .map(|InferOk { value: (), obligations }| {
-                obligations.into_iter().map(|o| o.into()).collect()
-            })
-            .map_err(|e| {
-                debug!(?e, "failed to sup");
-                NoSolution
-            })
+        value: ty::Binder<'tcx, T>,
+    ) -> T {
+        self.replace_bound_vars_with_fresh_vars(
+            DUMMY_SP,
+            LateBoundRegionConversionTime::HigherRankedType,
+            value,
+        )
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 5c1f3f02e93a8..00c7edf0ef8a3 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -6,7 +6,7 @@ use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime};
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::specialization_graph::LeafDef;
 use rustc_infer::traits::Reveal;
@@ -297,12 +297,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
     ) -> QueryResult<'tcx> {
         if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() {
             ecx.infcx.probe(|_| {
-                let assumption_projection_pred = ecx.infcx.replace_bound_vars_with_fresh_vars(
-                    DUMMY_SP,
-                    LateBoundRegionConversionTime::HigherRankedType,
-                    poly_projection_pred,
-                );
-                let nested_goals = ecx.infcx.sup(
+                let assumption_projection_pred =
+                    ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred);
+                let nested_goals = ecx.infcx.eq(
                     goal.param_env,
                     goal.predicate.projection_ty,
                     assumption_projection_pred.projection_ty,
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 4d94265dc07f5..d89759f4dd487 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -10,8 +10,8 @@ use rustc_hir::{Movability, Mutability};
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
+use rustc_middle::ty::TraitPredicate;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{ToPolyTraitRef, TraitPredicate};
 use rustc_span::DUMMY_SP;
 
 impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
@@ -67,10 +67,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() {
             // FIXME: Constness and polarity
             ecx.infcx.probe(|_| {
-                let nested_goals = ecx.infcx.sup(
+                let assumption_trait_pred =
+                    ecx.infcx.instantiate_bound_vars_with_infer(poly_trait_pred);
+                let nested_goals = ecx.infcx.eq(
                     goal.param_env,
-                    ty::Binder::dummy(goal.predicate.trait_ref),
-                    poly_trait_pred.to_poly_trait_ref(),
+                    goal.predicate.trait_ref,
+                    assumption_trait_pred.trait_ref,
                 )?;
                 ecx.evaluate_all_and_make_canonical_response(nested_goals)
             })

From f672436f04938da11c74664f6665f28018f0a390 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Wed, 18 Jan 2023 14:56:44 +0000
Subject: [PATCH 7/7] Handle structural traits more gracefully

---
 .../src/solve/trait_goals.rs                  | 248 +++---------------
 .../solve/trait_goals/structural_traits.rs    | 179 +++++++++++++
 2 files changed, 212 insertions(+), 215 deletions(-)
 create mode 100644 compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs

diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index d89759f4dd487..1ebcfd03c14ea 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 super::assembly::{self, Candidate, CandidateSource};
 use super::infcx_ext::InferCtxtExt;
 use super::{EvalCtxt, Goal, QueryResult};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Movability, Mutability};
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
@@ -14,6 +13,8 @@ use rustc_middle::ty::TraitPredicate;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::DUMMY_SP;
 
+mod structural_traits;
+
 impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     fn self_ty(self) -> Ty<'tcx> {
         self.self_ty()
@@ -85,11 +86,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        ecx.infcx.probe(|_| {
-            let constituent_tys =
-                instantiate_constituent_tys_for_auto_trait(ecx.infcx, goal.predicate.self_ty())?;
-            ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys)
-        })
+        ecx.probe_and_evaluate_goal_for_constituent_tys(
+            goal,
+            structural_traits::instantiate_constituent_tys_for_auto_trait,
+        )
     }
 
     fn consider_trait_alias_candidate(
@@ -112,44 +112,46 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        ecx.infcx.probe(|_| {
-            let constituent_tys =
-                instantiate_constituent_tys_for_sized_trait(ecx.infcx, goal.predicate.self_ty())?;
-            ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys)
-        })
+        ecx.probe_and_evaluate_goal_for_constituent_tys(
+            goal,
+            structural_traits::instantiate_constituent_tys_for_sized_trait,
+        )
     }
 
     fn consider_builtin_copy_clone_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        ecx.infcx.probe(|_| {
-            let constituent_tys = instantiate_constituent_tys_for_copy_clone_trait(
-                ecx.infcx,
-                goal.predicate.self_ty(),
-            )?;
-            ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys)
-        })
+        ecx.probe_and_evaluate_goal_for_constituent_tys(
+            goal,
+            structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
+        )
     }
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
-    fn evaluate_goal_for_constituent_tys_and_make_canonical_response(
+    /// Convenience function for traits that are structural, i.e. that only
+    /// have nested subgoals that only change the self type. Unlike other
+    /// evaluate-like helpers, this does a probe, so it doesn't need to be
+    /// wrapped in one.
+    fn probe_and_evaluate_goal_for_constituent_tys(
         &mut self,
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
-        constituent_tys: Vec<Ty<'tcx>>,
+        constituent_tys: impl Fn(&InferCtxt<'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
     ) -> QueryResult<'tcx> {
-        self.evaluate_all_and_make_canonical_response(
-            constituent_tys
-                .into_iter()
-                .map(|ty| {
-                    goal.with(
-                        self.tcx(),
-                        ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)),
-                    )
-                })
-                .collect(),
-        )
+        self.infcx.probe(|_| {
+            self.evaluate_all_and_make_canonical_response(
+                constituent_tys(self.infcx, goal.predicate.self_ty())?
+                    .into_iter()
+                    .map(|ty| {
+                        goal.with(
+                            self.tcx(),
+                            ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)),
+                        )
+                    })
+                    .collect(),
+            )
+        })
     }
 
     pub(super) fn compute_trait_goal(
@@ -227,187 +229,3 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         candidate
     }
 }
-
-// Calculates the constituent types of a type for `auto trait` purposes.
-//
-// For types with an "existential" binder, i.e. generator witnesses, we also
-// instantiate the binder with placeholders eagerly.
-fn instantiate_constituent_tys_for_auto_trait<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    ty: Ty<'tcx>,
-) -> Result<Vec<Ty<'tcx>>, NoSolution> {
-    let tcx = infcx.tcx;
-    match *ty.kind() {
-        ty::Uint(_)
-        | ty::Int(_)
-        | ty::Bool
-        | ty::Float(_)
-        | ty::FnDef(..)
-        | ty::FnPtr(_)
-        | ty::Str
-        | ty::Error(_)
-        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
-        | ty::Never
-        | ty::Char => Ok(vec![]),
-
-        ty::Placeholder(..)
-        | ty::Dynamic(..)
-        | ty::Param(..)
-        | ty::Foreign(..)
-        | ty::Alias(ty::Projection, ..)
-        | ty::Bound(..)
-        | ty::Infer(ty::TyVar(_)) => {
-            // FIXME: Do we need to mark anything as ambiguous here? Yeah?
-            Err(NoSolution)
-        }
-
-        ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
-
-        ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
-            Ok(vec![element_ty])
-        }
-
-        ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]),
-
-        ty::Tuple(ref tys) => {
-            // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
-            Ok(tys.iter().collect())
-        }
-
-        ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
-
-        ty::Generator(_, ref substs, _) => {
-            let generator_substs = substs.as_generator();
-            Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()])
-        }
-
-        ty::GeneratorWitness(types) => {
-            Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
-        }
-
-        // For `PhantomData<T>`, we pass `T`.
-        ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]),
-
-        ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()),
-
-        ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
-            // We can resolve the `impl Trait` to its concrete type,
-            // which enforces a DAG between the functions requiring
-            // the auto trait bounds in question.
-            Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)])
-        }
-    }
-}
-
-fn instantiate_constituent_tys_for_sized_trait<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    ty: Ty<'tcx>,
-) -> Result<Vec<Ty<'tcx>>, NoSolution> {
-    match *ty.kind() {
-        ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
-        | ty::Uint(_)
-        | ty::Int(_)
-        | ty::Bool
-        | ty::Float(_)
-        | ty::FnDef(..)
-        | ty::FnPtr(_)
-        | ty::RawPtr(..)
-        | ty::Char
-        | ty::Ref(..)
-        | ty::Generator(..)
-        | ty::GeneratorWitness(..)
-        | ty::Array(..)
-        | ty::Closure(..)
-        | ty::Never
-        | ty::Dynamic(_, _, ty::DynStar)
-        | ty::Error(_) => Ok(vec![]),
-
-        ty::Str
-        | ty::Slice(_)
-        | ty::Dynamic(..)
-        | ty::Foreign(..)
-        | ty::Alias(..)
-        | ty::Param(_) => Err(NoSolution),
-
-        ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
-
-        ty::Placeholder(..)
-        | ty::Bound(..)
-        | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
-
-        ty::Tuple(tys) => Ok(tys.to_vec()),
-
-        ty::Adt(def, substs) => {
-            let sized_crit = def.sized_constraint(infcx.tcx);
-            Ok(sized_crit
-                .0
-                .iter()
-                .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs))
-                .collect())
-        }
-    }
-}
-
-fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    ty: Ty<'tcx>,
-) -> Result<Vec<Ty<'tcx>>, NoSolution> {
-    match *ty.kind() {
-        ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
-        | ty::FnDef(..)
-        | ty::FnPtr(_)
-        | ty::Error(_) => Ok(vec![]),
-
-        // Implementations are provided in core
-        ty::Uint(_)
-        | ty::Int(_)
-        | ty::Bool
-        | ty::Float(_)
-        | ty::Char
-        | ty::RawPtr(..)
-        | ty::Never
-        | ty::Ref(_, _, Mutability::Not)
-        | ty::Array(..) => Err(NoSolution),
-
-        ty::Dynamic(..)
-        | ty::Str
-        | ty::Slice(_)
-        | ty::Generator(_, _, Movability::Static)
-        | ty::Foreign(..)
-        | ty::Ref(_, _, Mutability::Mut)
-        | ty::Adt(_, _)
-        | ty::Alias(_, _)
-        | ty::Param(_) => Err(NoSolution),
-
-        ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
-
-        ty::Placeholder(..)
-        | ty::Bound(..)
-        | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
-
-        ty::Tuple(tys) => Ok(tys.to_vec()),
-
-        ty::Closure(_, substs) => match *substs.as_closure().tupled_upvars_ty().kind() {
-            ty::Tuple(tys) => Ok(tys.to_vec()),
-            ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
-            _ => bug!(),
-        },
-
-        ty::Generator(_, substs, Movability::Movable) => {
-            if infcx.tcx.features().generator_clone {
-                let generator = substs.as_generator();
-                match *generator.tupled_upvars_ty().kind() {
-                    ty::Tuple(tys) => Ok(tys.iter().chain([generator.witness()]).collect()),
-                    ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
-                    _ => bug!(),
-                }
-            } else {
-                Err(NoSolution)
-            }
-        }
-
-        ty::GeneratorWitness(types) => {
-            Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
-        }
-    }
-}
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
new file mode 100644
index 0000000000000..bbc0c77253278
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
@@ -0,0 +1,179 @@
+use rustc_hir::{Movability, Mutability};
+use rustc_infer::{infer::InferCtxt, traits::query::NoSolution};
+use rustc_middle::ty::{self, Ty};
+
+// Calculates the constituent types of a type for `auto trait` purposes.
+//
+// For types with an "existential" binder, i.e. generator witnesses, we also
+// instantiate the binder with placeholders eagerly.
+pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Result<Vec<Ty<'tcx>>, NoSolution> {
+    let tcx = infcx.tcx;
+    match *ty.kind() {
+        ty::Uint(_)
+        | ty::Int(_)
+        | ty::Bool
+        | ty::Float(_)
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::Str
+        | ty::Error(_)
+        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+        | ty::Never
+        | ty::Char => Ok(vec![]),
+
+        ty::Placeholder(..)
+        | ty::Dynamic(..)
+        | ty::Param(..)
+        | ty::Foreign(..)
+        | ty::Alias(ty::Projection, ..)
+        | ty::Bound(..)
+        | ty::Infer(ty::TyVar(_)) => {
+            // FIXME: Do we need to mark anything as ambiguous here? Yeah?
+            Err(NoSolution)
+        }
+
+        ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
+
+        ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
+            Ok(vec![element_ty])
+        }
+
+        ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]),
+
+        ty::Tuple(ref tys) => {
+            // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
+            Ok(tys.iter().collect())
+        }
+
+        ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
+
+        ty::Generator(_, ref substs, _) => {
+            let generator_substs = substs.as_generator();
+            Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()])
+        }
+
+        ty::GeneratorWitness(types) => {
+            Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
+        }
+
+        // For `PhantomData<T>`, we pass `T`.
+        ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]),
+
+        ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()),
+
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
+            // We can resolve the `impl Trait` to its concrete type,
+            // which enforces a DAG between the functions requiring
+            // the auto trait bounds in question.
+            Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)])
+        }
+    }
+}
+
+pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Result<Vec<Ty<'tcx>>, NoSolution> {
+    match *ty.kind() {
+        ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+        | ty::Uint(_)
+        | ty::Int(_)
+        | ty::Bool
+        | ty::Float(_)
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::RawPtr(..)
+        | ty::Char
+        | ty::Ref(..)
+        | ty::Generator(..)
+        | ty::GeneratorWitness(..)
+        | ty::Array(..)
+        | ty::Closure(..)
+        | ty::Never
+        | ty::Dynamic(_, _, ty::DynStar)
+        | ty::Error(_) => Ok(vec![]),
+
+        ty::Str
+        | ty::Slice(_)
+        | ty::Dynamic(..)
+        | ty::Foreign(..)
+        | ty::Alias(..)
+        | ty::Param(_) => Err(NoSolution),
+
+        ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
+
+        ty::Placeholder(..)
+        | ty::Bound(..)
+        | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
+
+        ty::Tuple(tys) => Ok(tys.to_vec()),
+
+        ty::Adt(def, substs) => {
+            let sized_crit = def.sized_constraint(infcx.tcx);
+            Ok(sized_crit
+                .0
+                .iter()
+                .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs))
+                .collect())
+        }
+    }
+}
+
+pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Result<Vec<Ty<'tcx>>, NoSolution> {
+    match *ty.kind() {
+        ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::Error(_) => Ok(vec![]),
+
+        // Implementations are provided in core
+        ty::Uint(_)
+        | ty::Int(_)
+        | ty::Bool
+        | ty::Float(_)
+        | ty::Char
+        | ty::RawPtr(..)
+        | ty::Never
+        | ty::Ref(_, _, Mutability::Not)
+        | ty::Array(..) => Err(NoSolution),
+
+        ty::Dynamic(..)
+        | ty::Str
+        | ty::Slice(_)
+        | ty::Generator(_, _, Movability::Static)
+        | ty::Foreign(..)
+        | ty::Ref(_, _, Mutability::Mut)
+        | ty::Adt(_, _)
+        | ty::Alias(_, _)
+        | ty::Param(_) => Err(NoSolution),
+
+        ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
+
+        ty::Placeholder(..)
+        | ty::Bound(..)
+        | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
+
+        ty::Tuple(tys) => Ok(tys.to_vec()),
+
+        ty::Closure(_, substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
+
+        ty::Generator(_, substs, Movability::Movable) => {
+            if infcx.tcx.features().generator_clone {
+                let generator = substs.as_generator();
+                Ok(vec![generator.tupled_upvars_ty(), generator.witness()])
+            } else {
+                Err(NoSolution)
+            }
+        }
+
+        ty::GeneratorWitness(types) => {
+            Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
+        }
+    }
+}