about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-02-16 03:04:08 +0000
committerMichael Goulet <michael@errs.io>2023-02-18 19:45:02 +0000
commit6402c98621ab620a16adac072abc10779cf60573 (patch)
tree71a6f9634cdff7db113f24adfd0e48459198e13a
parent82b52056fe99705b4234c5781eada2bd7ae6042e (diff)
downloadrust-6402c98621ab620a16adac072abc10779cf60573.tar.gz
rust-6402c98621ab620a16adac072abc10779cf60573.zip
Add consider_implied_clause
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly.rs30
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs117
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs52
3 files changed, 97 insertions, 102 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index a9e0c5509a5..841169ac78d 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -90,28 +90,20 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
 
     fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
 
-    fn consider_impl_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        goal: Goal<'tcx, Self>,
-        impl_def_id: DefId,
-    ) -> QueryResult<'tcx>;
-
-    // Consider a predicate we know holds (`assumption`) against a goal we're trying to prove.
-    fn consider_assumption(
+    // Consider a clause, which consists of a "assumption" and some "requirements",
+    // to satisfy a goal. If the requirements hold, then attempt to satisfy our
+    // goal by equating it with the assumption.
+    fn consider_implied_clause(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Predicate<'tcx>,
-    ) -> QueryResult<'tcx> {
-        Self::consider_assumption_with_certainty(ecx, goal, assumption, Certainty::Yes)
-    }
+        requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
+    ) -> QueryResult<'tcx>;
 
-    // Consider a predicate we know holds (`assumption`) against a goal, unifying with
-    // the `assumption_certainty` if it satisfies the goal.
-    fn consider_assumption_with_certainty(
+    fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
-        assumption: ty::Predicate<'tcx>,
-        assumption_certainty: Certainty,
+        impl_def_id: DefId,
     ) -> QueryResult<'tcx>;
 
     // A type implements an `auto trait` if its components do as well. These components
@@ -367,7 +359,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) {
+            match G::consider_implied_clause(self, goal, assumption, []) {
                 Ok(result) => {
                     candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
                 }
@@ -414,7 +406,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_assumption(self, goal, assumption) {
+            match G::consider_implied_clause(self, goal, assumption, []) {
                 Ok(result) => {
                     candidates.push(Candidate { source: CandidateSource::AliasBound, result })
                 }
@@ -464,7 +456,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_implied_clause(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 adf8a1690c8..48153b465b7 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -168,6 +168,37 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         self.trait_def_id(tcx)
     }
 
+    fn consider_implied_clause(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        assumption: ty::Predicate<'tcx>,
+        requirements: impl IntoIterator<Item = Goal<'tcx, 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.infcx.probe(|_| {
+                let assumption_projection_pred =
+                    ecx.infcx.instantiate_binder_with_infer(poly_projection_pred);
+                let mut nested_goals = ecx.infcx.eq(
+                    goal.param_env,
+                    goal.predicate.projection_ty,
+                    assumption_projection_pred.projection_ty,
+                )?;
+                nested_goals.extend(requirements);
+                let subst_certainty = ecx.evaluate_all(nested_goals)?;
+
+                ecx.eq_term_and_make_canonical_response(
+                    goal,
+                    subst_certainty,
+                    assumption_projection_pred.term,
+                )
+            })
+        } else {
+            Err(NoSolution)
+        }
+    }
+
     fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
@@ -260,36 +291,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         })
     }
 
-    fn consider_assumption_with_certainty(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        goal: Goal<'tcx, Self>,
-        assumption: ty::Predicate<'tcx>,
-        assumption_certainty: Certainty,
-    ) -> 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.infcx.probe(|_| {
-                let assumption_projection_pred =
-                    ecx.infcx.instantiate_binder_with_infer(poly_projection_pred);
-                let nested_goals = ecx.infcx.eq(
-                    goal.param_env,
-                    goal.predicate.projection_ty,
-                    assumption_projection_pred.projection_ty,
-                )?;
-                let subst_certainty = ecx.evaluate_all(nested_goals)?;
-
-                ecx.eq_term_and_make_canonical_response(
-                    goal,
-                    subst_certainty.unify_and(assumption_certainty),
-                    assumption_projection_pred.term,
-                )
-            })
-        } else {
-            Err(NoSolution)
-        }
-    }
-
     fn consider_auto_trait_candidate(
         _ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -331,31 +332,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         goal_kind: ty::ClosureKind,
     ) -> QueryResult<'tcx> {
         let tcx = ecx.tcx();
-        if let Some(tupled_inputs_and_output) =
-            structural_traits::extract_tupled_inputs_and_output_from_callable(
-                tcx,
-                goal.predicate.self_ty(),
-                goal_kind,
-            )?
-        {
-            // A built-in `Fn` trait needs to check that its output is `Sized`
-            // (FIXME: technically we only need to check this if the type is a fn ptr...)
-            let output_is_sized_pred = tupled_inputs_and_output
-                .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
-            let (_, output_is_sized_certainty) =
-                ecx.evaluate_goal(goal.with(tcx, output_is_sized_pred))?;
-
-            let pred = tupled_inputs_and_output
-                .map_bound(|(inputs, output)| ty::ProjectionPredicate {
-                    projection_ty: tcx
-                        .mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]),
-                    term: output.into(),
-                })
-                .to_predicate(tcx);
-            Self::consider_assumption_with_certainty(ecx, goal, pred, output_is_sized_certainty)
-        } else {
-            ecx.make_canonical_response(Certainty::AMBIGUOUS)
-        }
+        let Some(tupled_inputs_and_output) =
+        structural_traits::extract_tupled_inputs_and_output_from_callable(
+            tcx,
+            goal.predicate.self_ty(),
+            goal_kind,
+        )? else {
+        return ecx.make_canonical_response(Certainty::AMBIGUOUS);
+    };
+        let output_is_sized_pred = tupled_inputs_and_output
+            .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
+
+        let pred = tupled_inputs_and_output
+            .map_bound(|(inputs, output)| ty::ProjectionPredicate {
+                projection_ty: tcx
+                    .mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]),
+                term: output.into(),
+            })
+            .to_predicate(tcx);
+        // A built-in `Fn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
+        Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
     }
 
     fn consider_builtin_tuple_candidate(
@@ -474,7 +471,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
 
         let term = substs.as_generator().return_ty().into();
 
-        Self::consider_assumption(
+        Self::consider_implied_clause(
             ecx,
             goal,
             ty::Binder::dummy(ty::ProjectionPredicate {
@@ -482,6 +479,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                 term,
             })
             .to_predicate(tcx),
+            // Technically, we need to check that the future type is Sized,
+            // but that's already proven by the generator being WF.
+            [],
         )
     }
 
@@ -511,7 +511,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
             bug!("unexpected associated item `<{self_ty} as Generator>::{name}`")
         };
 
-        Self::consider_assumption(
+        Self::consider_implied_clause(
             ecx,
             goal,
             ty::Binder::dummy(ty::ProjectionPredicate {
@@ -521,6 +521,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                 term,
             })
             .to_predicate(tcx),
+            // Technically, we need to check that the future type is Sized,
+            // but that's already proven by the generator being WF.
+            [],
         )
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index dd47a5ae150..f2f25ef850a 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -62,11 +62,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         })
     }
 
-    fn consider_assumption_with_certainty(
+    fn consider_implied_clause(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Predicate<'tcx>,
-        assumption_certainty: Certainty,
+        requirements: impl IntoIterator<Item = Goal<'tcx, 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()
@@ -75,14 +75,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             ecx.infcx.probe(|_| {
                 let assumption_trait_pred =
                     ecx.infcx.instantiate_binder_with_infer(poly_trait_pred);
-                let nested_goals = ecx.infcx.eq(
+                let mut nested_goals = ecx.infcx.eq(
                     goal.param_env,
                     goal.predicate.trait_ref,
                     assumption_trait_pred.trait_ref,
                 )?;
-                ecx.evaluate_all(nested_goals).and_then(|certainty| {
-                    ecx.make_canonical_response(certainty.unify_and(assumption_certainty))
-                })
+                nested_goals.extend(requirements);
+                ecx.evaluate_all_and_make_canonical_response(nested_goals)
             })
         } else {
             Err(NoSolution)
@@ -178,29 +177,25 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         goal_kind: ty::ClosureKind,
     ) -> QueryResult<'tcx> {
         let tcx = ecx.tcx();
-        if let Some(tupled_inputs_and_output) =
+        let Some(tupled_inputs_and_output) =
             structural_traits::extract_tupled_inputs_and_output_from_callable(
                 tcx,
                 goal.predicate.self_ty(),
                 goal_kind,
-            )?
-        {
-            // A built-in `Fn` trait needs to check that its output is `Sized`
-            // (FIXME: technically we only need to check this if the type is a fn ptr...)
-            let output_is_sized_pred = tupled_inputs_and_output
-                .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
-            let (_, output_is_sized_certainty) =
-                ecx.evaluate_goal(goal.with(tcx, output_is_sized_pred))?;
-
-            let pred = tupled_inputs_and_output
-                .map_bound(|(inputs, _)| {
-                    tcx.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
-                })
-                .to_predicate(tcx);
-            Self::consider_assumption_with_certainty(ecx, goal, pred, output_is_sized_certainty)
-        } else {
-            ecx.make_canonical_response(Certainty::AMBIGUOUS)
-        }
+            )? else {
+            return ecx.make_canonical_response(Certainty::AMBIGUOUS);
+        };
+        let output_is_sized_pred = tupled_inputs_and_output
+            .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
+
+        let pred = tupled_inputs_and_output
+            .map_bound(|(inputs, _)| {
+                tcx.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
+            })
+            .to_predicate(tcx);
+        // A built-in `Fn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
+        Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
     }
 
     fn consider_builtin_tuple_candidate(
@@ -236,6 +231,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         }
 
         // Async generator unconditionally implement `Future`
+        // Technically, we need to check that the future output type is Sized,
+        // but that's already proven by the generator being WF.
         ecx.make_canonical_response(Certainty::Yes)
     }
 
@@ -255,13 +252,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         }
 
         let generator = substs.as_generator();
-        Self::consider_assumption(
+        Self::consider_implied_clause(
             ecx,
             goal,
             ty::Binder::dummy(
                 tcx.mk_trait_ref(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
             )
             .to_predicate(tcx),
+            // Technically, we need to check that the generator types are Sized,
+            // but that's already proven by the generator being WF.
+            [],
         )
     }