]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_trait_selection/src/traits/select/mod.rs
Rollup merge of #89876 - AlexApps99:const_ops, r=oli-obk
[rust.git] / compiler / rustc_trait_selection / src / traits / select / mod.rs
index 94c4bc55f799b7e63f7f73a70fa34f3b217e1276..1b26e38fe0e4d437b0f5245d16949e8c6c72fc87 100644 (file)
@@ -20,7 +20,7 @@
 use super::Selection;
 use super::SelectionResult;
 use super::TraitQueryMode;
-use super::{ErrorReporting, Overflow, SelectionError, Unimplemented};
+use super::{ErrorReporting, Overflow, SelectionError};
 use super::{ObligationCause, PredicateObligation, TraitObligation};
 
 use crate::infer::{InferCtxt, InferOk, TypeFreshener};
@@ -357,18 +357,16 @@ pub fn select(
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> SelectionResult<'tcx, Selection<'tcx>> {
-        debug_assert!(!obligation.predicate.has_escaping_bound_vars());
-
-        let pec = &ProvisionalEvaluationCache::default();
-        let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
-
-        let candidate = match self.candidate_from_obligation(&stack) {
+        let candidate = match self.select_from_obligation(obligation) {
             Err(SelectionError::Overflow) => {
                 // In standard mode, overflow must have been caught and reported
                 // earlier.
                 assert!(self.query_mode == TraitQueryMode::Canonical);
                 return Err(SelectionError::Overflow);
             }
+            Err(SelectionError::Ambiguous(_)) => {
+                return Ok(None);
+            }
             Err(e) => {
                 return Err(e);
             }
@@ -391,6 +389,18 @@ pub fn select(
         }
     }
 
+    crate fn select_from_obligation(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+        debug_assert!(!obligation.predicate.has_escaping_bound_vars());
+
+        let pec = &ProvisionalEvaluationCache::default();
+        let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
+
+        self.candidate_from_obligation(&stack)
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // EVALUATION
     //
@@ -915,6 +925,7 @@ fn evaluate_stack<'o>(
 
         match self.candidate_from_obligation(stack) {
             Ok(Some(c)) => self.evaluate_candidate(stack, &c),
+            Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig),
             Ok(None) => Ok(EvaluatedToAmbig),
             Err(Overflow) => Err(OverflowError::Canonical),
             Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
@@ -1117,24 +1128,57 @@ fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
         (result, dep_node)
     }
 
-    /// filter_impls filters candidates that have a positive impl for a negative goal and a
-    /// negative impl for a positive goal
+    /// filter_impls filters constant trait obligations and candidates that have a positive impl
+    /// for a negative goal and a negative impl for a positive goal
     #[instrument(level = "debug", skip(self))]
     fn filter_impls(
         &mut self,
-        candidates: &mut Vec<SelectionCandidate<'tcx>>,
-        stack: &TraitObligationStack<'o, 'tcx>,
-    ) {
+        candidates: Vec<SelectionCandidate<'tcx>>,
+        obligation: &TraitObligation<'tcx>,
+    ) -> Vec<SelectionCandidate<'tcx>> {
         let tcx = self.tcx();
-        candidates.retain(|candidate| {
+        let mut result = Vec::with_capacity(candidates.len());
+
+        for candidate in candidates {
+            // Respect const trait obligations
+            if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
+                match candidate {
+                    // const impl
+                    ImplCandidate(def_id)
+                        if tcx.impl_constness(def_id) == hir::Constness::Const => {}
+                    // const param
+                    ParamCandidate((
+                        ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
+                        _,
+                    )) => {}
+                    // auto trait impl
+                    AutoImplCandidate(..) => {}
+                    // generator, this will raise error in other places
+                    // or ignore error with const_async_blocks feature
+                    GeneratorCandidate => {}
+                    // FnDef where the function is const
+                    FnPointerCandidate { is_const: true } => {}
+                    ConstDropCandidate => {}
+                    _ => {
+                        // reject all other types of candidates
+                        continue;
+                    }
+                }
+            }
+
             if let ImplCandidate(def_id) = candidate {
-                ty::ImplPolarity::Reservation == tcx.impl_polarity(*def_id)
-                    || stack.obligation.polarity() == tcx.impl_polarity(*def_id)
+                if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id)
+                    || obligation.polarity() == tcx.impl_polarity(def_id)
                     || self.allow_negative_impls
+                {
+                    result.push(candidate);
+                }
             } else {
-                true
+                result.push(candidate);
             }
-        });
+        }
+
+        result
     }
 
     /// filter_reservation_impls filter reservation impl for any goal as ambiguous
@@ -1145,30 +1189,6 @@ fn filter_reservation_impls(
         obligation: &TraitObligation<'tcx>,
     ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
         let tcx = self.tcx();
-        // Respect const trait obligations
-        if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
-            match candidate {
-                // const impl
-                ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
-                // const param
-                ParamCandidate((
-                    ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
-                    _,
-                )) => {}
-                // auto trait impl
-                AutoImplCandidate(..) => {}
-                // generator, this will raise error in other places
-                // or ignore error with const_async_blocks feature
-                GeneratorCandidate => {}
-                // FnDef where the function is const
-                FnPointerCandidate { is_const: true } => {}
-                ConstDropCandidate => {}
-                _ => {
-                    // reject all other types of candidates
-                    return Err(Unimplemented);
-                }
-            }
-        }
         // Treat reservation impls as ambiguity.
         if let ImplCandidate(def_id) = candidate {
             if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
@@ -1178,7 +1198,7 @@ fn filter_reservation_impls(
                     let value = attr.and_then(|a| a.value_str());
                     if let Some(value) = value {
                         debug!(
-                            "filter_impls: \
+                            "filter_reservation_impls: \
                                  reservation impl ambiguity on {:?}",
                             def_id
                         );