about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDeadbeef <ent3rm4n@gmail.com>2021-07-26 10:52:17 +0800
committerDeadbeef <ent3rm4n@gmail.com>2021-08-13 09:28:50 +0000
commit01bb3710b5e7114a470f07b6d0463a70ae728607 (patch)
treee59919553f05738dcc24ba2cb38b8ec4fe59b444
parenta00f2bcf5c8d98852d6cfda2468185eda41ff2ba (diff)
downloadrust-01bb3710b5e7114a470f07b6d0463a70ae728607.tar.gz
rust-01bb3710b5e7114a470f07b6d0463a70ae728607.zip
Pass constness to SelectionContext
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs26
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs65
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs4
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs11
5 files changed, 101 insertions, 23 deletions
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index 2710debea94..d60388b31c1 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -1,5 +1,6 @@
 use crate::infer::InferCtxt;
 use crate::traits::Obligation;
+use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness};
 
@@ -49,11 +50,28 @@ pub trait TraitEngine<'tcx>: 'tcx {
         infcx: &InferCtxt<'_, 'tcx>,
     ) -> Result<(), Vec<FulfillmentError<'tcx>>>;
 
+    fn select_all_with_constness_or_error(
+        &mut self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        _constness: hir::Constness,
+    ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+        self.select_all_or_error(infcx)
+    }
+
     fn select_where_possible(
         &mut self,
         infcx: &InferCtxt<'_, 'tcx>,
     ) -> Result<(), Vec<FulfillmentError<'tcx>>>;
 
+    // FIXME this should not provide a default body for chalk as chalk should be updated
+    fn select_with_constness_where_possible(
+        &mut self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        _constness: hir::Constness,
+    ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+        self.select_where_possible(infcx)
+    }
+
     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index cf50c34530e..4c5d8b5ec79 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -3,6 +3,7 @@ use rustc_data_structures::obligation_forest::ProcessResult;
 use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
 use rustc_errors::ErrorReported;
+use rustc_hir as hir;
 use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
 use rustc_middle::mir::abstract_const::NotConstEvaluatable;
 use rustc_middle::mir::interpret::ErrorHandled;
@@ -228,6 +229,22 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         if errors.is_empty() { Ok(()) } else { Err(errors) }
     }
 
+    fn select_all_with_constness_or_error(
+        &mut self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        constness: rustc_hir::Constness,
+    ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+        self.select_with_constness_where_possible(infcx, constness)?;
+
+        let errors: Vec<_> = self
+            .predicates
+            .to_errors(CodeAmbiguity)
+            .into_iter()
+            .map(to_fulfillment_error)
+            .collect();
+        if errors.is_empty() { Ok(()) } else { Err(errors) }
+    }
+
     fn select_where_possible(
         &mut self,
         infcx: &InferCtxt<'_, 'tcx>,
@@ -236,6 +253,15 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         self.select(&mut selcx)
     }
 
+    fn select_with_constness_where_possible(
+        &mut self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        constness: hir::Constness,
+    ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+        let mut selcx = SelectionContext::with_constness(infcx, constness);
+        self.select(&mut selcx)
+    }
+
     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
         self.predicates.map_pending_obligations(|o| o.obligation.clone())
     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 5321993f0ce..f7c66f8b284 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -130,6 +130,9 @@ pub struct SelectionContext<'cx, 'tcx> {
     /// and a negative impl
     allow_negative_impls: bool,
 
+    /// Do we only want const impls when we have a const trait predicate?
+    const_impls_required: bool,
+
     /// The mode that trait queries run in, which informs our error handling
     /// policy. In essence, canonicalized queries need their errors propagated
     /// rather than immediately reported because we do not have accurate spans.
@@ -221,6 +224,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             intercrate: false,
             intercrate_ambiguity_causes: None,
             allow_negative_impls: false,
+            const_impls_required: false,
             query_mode: TraitQueryMode::Standard,
         }
     }
@@ -232,6 +236,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             intercrate: true,
             intercrate_ambiguity_causes: None,
             allow_negative_impls: false,
+            const_impls_required: false,
             query_mode: TraitQueryMode::Standard,
         }
     }
@@ -247,6 +252,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             intercrate: false,
             intercrate_ambiguity_causes: None,
             allow_negative_impls,
+            const_impls_required: false,
             query_mode: TraitQueryMode::Standard,
         }
     }
@@ -262,10 +268,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             intercrate: false,
             intercrate_ambiguity_causes: None,
             allow_negative_impls: false,
+            const_impls_required: false,
             query_mode,
         }
     }
 
+    pub fn with_constness(
+        infcx: &'cx InferCtxt<'cx, 'tcx>,
+        constness: hir::Constness,
+    ) -> SelectionContext<'cx, 'tcx> {
+        SelectionContext {
+            infcx,
+            freshener: infcx.freshener_keep_static(),
+            intercrate: false,
+            intercrate_ambiguity_causes: None,
+            allow_negative_impls: false,
+            const_impls_required: matches!(constness, hir::Constness::Const),
+            query_mode: TraitQueryMode::Standard,
+        }
+    }
+
     /// Enables tracking of intercrate ambiguity causes. These are
     /// used in coherence to give improved diagnostics. We don't do
     /// this until we detect a coherence error because it can lead to
@@ -1024,26 +1046,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
         let tcx = self.tcx();
         // Respect const trait obligations
-        if let hir::Constness::Const = obligation.predicate.skip_binder().constness {
-            if Some(obligation.predicate.skip_binder().trait_ref.def_id)
-                != tcx.lang_items().sized_trait()
-            // const Sized bounds are skipped
-            {
-                match candidate {
-                    // const impl
-                    ImplCandidate(def_id)
-                        if tcx.impl_constness(def_id) == hir::Constness::Const => {}
-                    // const param
-                    ParamCandidate(ty::ConstnessAnd {
-                        constness: hir::Constness::Const, ..
-                    }) => {}
-                    // auto trait impl
-                    AutoImplCandidate(..) => {}
-                    // FIXME check if this is right, but this would allow Sized impls
-                    // BuiltinCandidate { .. } => {}
-                    _ => {
-                        // reject all other types of candidates
-                        return Err(Unimplemented);
+        if self.const_impls_required {
+            if let hir::Constness::Const = obligation.predicate.skip_binder().constness {
+                if Some(obligation.predicate.skip_binder().trait_ref.def_id)
+                    != tcx.lang_items().sized_trait()
+                // const Sized bounds are skipped
+                {
+                    match candidate {
+                        // const impl
+                        ImplCandidate(def_id)
+                            if tcx.impl_constness(def_id) == hir::Constness::Const => {}
+                        // const param
+                        ParamCandidate(ty::ConstnessAnd {
+                            constness: hir::Constness::Const,
+                            ..
+                        }) => {}
+                        // auto trait impl
+                        AutoImplCandidate(..) => {}
+                        // FIXME check if this is right, but this would allow Sized impls
+                        // BuiltinCandidate { .. } => {}
+                        _ => {
+                            // reject all other types of candidates
+                            return Err(Unimplemented);
+                        }
                     }
                 }
             }
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 01890f75026..0ce2746b128 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -1354,7 +1354,9 @@ pub fn check_type_bounds<'tcx>(
 
         // Check that all obligations are satisfied by the implementation's
         // version.
-        if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
+        if let Err(ref errors) =
+            inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness)
+        {
             infcx.report_fulfillment_errors(errors, None, false);
             return Err(ErrorReported);
         }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index ee226aa82c6..c13901ae8be 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -714,7 +714,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub(in super::super) fn select_all_obligations_or_error(&self) {
         debug!("select_all_obligations_or_error");
-        if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {
+        if let Err(errors) = self
+            .fulfillment_cx
+            .borrow_mut()
+            .select_all_with_constness_or_error(&self, self.inh.constness)
+        {
             self.report_fulfillment_errors(&errors, self.inh.body_id, false);
         }
     }
@@ -725,7 +729,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fallback_has_occurred: bool,
         mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
     ) {
-        let result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
+        let result = self
+            .fulfillment_cx
+            .borrow_mut()
+            .select_with_constness_where_possible(self, self.inh.constness);
         if let Err(mut errors) = result {
             mutate_fulfillment_errors(&mut errors);
             self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);