]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_trait_selection/src/solve/assembly.rs
Rollup merge of #107304 - Nilstrieb:ᐸTy as PartialEqᐳ::eq because what else are we...
[rust.git] / compiler / rustc_trait_selection / src / solve / assembly.rs
index cd6e4d2bccd5cfdae00dae9e2fdb09514c1431a2..0b642fcba281249da01b21d4af4ece7fe96c2636 100644 (file)
@@ -1,9 +1,10 @@
 //! Code shared by trait and projection goals for candidate assembly.
 
 use super::infcx_ext::InferCtxtExt;
-use super::{CanonicalResponse, Certainty, EvalCtxt, Goal};
+use super::{CanonicalResponse, Certainty, 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;
@@ -78,7 +79,7 @@ pub(super) enum CandidateSource {
     AliasBound(usize),
 }
 
-pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy {
+pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
     fn self_ty(self) -> Ty<'tcx>;
 
     fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self;
@@ -89,24 +90,73 @@ fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
         impl_def_id: DefId,
-    ) -> Result<Certainty, NoSolution>;
+    ) -> QueryResult<'tcx>;
+
+    fn consider_assumption(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        assumption: ty::Predicate<'tcx>,
+    ) -> QueryResult<'tcx>;
+
+    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>,
-    ) -> Result<Certainty, NoSolution>;
+    ) -> QueryResult<'tcx>;
 
-    fn consider_assumption(
+    fn consider_builtin_copy_clone_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
-        assumption: ty::Predicate<'tcx>,
-    ) -> Result<Certainty, NoSolution>;
+    ) -> QueryResult<'tcx>;
+
+    fn consider_builtin_pointer_sized_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
+    fn consider_builtin_fn_trait_candidates(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        kind: ty::ClosureKind,
+    ) -> QueryResult<'tcx>;
+
+    fn consider_builtin_tuple_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
+    fn consider_builtin_pointee_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,
         goal: Goal<'tcx, G>,
     ) -> Vec<Candidate<'tcx>> {
+        debug_assert_eq!(goal, self.infcx.resolve_vars_if_possible(goal));
+
+        // HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule,
+        // object bound, alias bound, etc. We are unable to determine this until we can at
+        // least structually resolve the type one layer.
+        if goal.predicate.self_ty().is_ty_var() {
+            return vec![Candidate {
+                source: CandidateSource::BuiltinImpl,
+                result: self.make_canonical_response(Certainty::AMBIGUOUS).unwrap(),
+            }];
+        }
+
         let mut candidates = Vec::new();
 
         self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates);
@@ -119,6 +169,8 @@ pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
 
         self.assemble_alias_bound_candidates(goal, &mut candidates);
 
+        self.assemble_object_bound_candidates(goal, &mut candidates);
+
         candidates
     }
 
@@ -150,6 +202,7 @@ fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>(
                 Ok((_, certainty)) => certainty,
                 Err(NoSolution) => return,
             };
+            let normalized_ty = self.infcx.resolve_vars_if_possible(normalized_ty);
 
             // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate.
             // This doesn't work as long as we use `CandidateSource` in winnowing.
@@ -180,9 +233,7 @@ fn assemble_impl_candidates<G: GoalKind<'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) => (),
@@ -197,13 +248,29 @@ fn assemble_builtin_impl_candidates<G: GoalKind<'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 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 if lang_items.pointer_sized() == Some(trait_def_id) {
+            G::consider_builtin_pointer_sized_candidate(self, goal)
+        } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) {
+            G::consider_builtin_fn_trait_candidates(self, goal, kind)
+        } else if lang_items.tuple_trait() == Some(trait_def_id) {
+            G::consider_builtin_tuple_candidate(self, goal)
+        } else if lang_items.pointee_trait() == Some(trait_def_id) {
+            G::consider_builtin_pointee_candidate(self, goal)
         } else {
             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 +284,7 @@ fn assemble_param_env_candidates<G: GoalKind<'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 +333,7 @@ fn assemble_alias_bound_candidates<G: GoalKind<'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 })
                 }
@@ -278,4 +341,52 @@ fn assemble_alias_bound_candidates<G: GoalKind<'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) => (),
+            }
+        }
+    }
 }