about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAravind Gollakota <aravindprasant@gmail.com>2018-04-19 02:28:03 -0500
committerAravind Gollakota <aravindprasant@gmail.com>2018-04-26 20:28:30 -0500
commite5535fc7ddf73f03c3adf2ea4097a171b2f5587f (patch)
tree3aea4402750fb15ab98c31fdbcd7904141c62675 /src
parent3dd26b8a3ef9e10dd92f1c958e97493dfbd8788d (diff)
downloadrust-e5535fc7ddf73f03c3adf2ea4097a171b2f5587f.tar.gz
rust-e5535fc7ddf73f03c3adf2ea4097a171b2f5587f.zip
Introduce trait query mode and use it to set overflow error handling policy in traits::select
Diffstat (limited to 'src')
-rw-r--r--src/librustc/traits/mod.rs13
-rw-r--r--src/librustc/traits/select.rs56
-rw-r--r--src/librustc_traits/evaluate_obligation.rs4
3 files changed, 60 insertions, 13 deletions
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index f09981dd8fc..6a8a000b58a 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -74,6 +74,19 @@ pub enum IntercrateMode {
     Fixed
 }
 
+// The mode that trait queries run in
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum TraitQueryMode {
+    // Standard/un-canonicalized queries get accurate
+    // spans etc. passed in and hence can do reasonable
+    // error reporting on their own.
+    Standard,
+    // Canonicalized queries get dummy spans and hence
+    // must generally propagate errors to
+    // pre-canonicalization callsites.
+    Canonical,
+}
+
 /// An `Obligation` represents some trait reference (e.g. `int:Eq`) for
 /// which the vtable must be found.  The process of finding a vtable is
 /// called "resolving" the `Obligation`. This process consists of
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index aae21e62051..342b163b2f7 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -17,7 +17,7 @@ use self::EvaluationResult::*;
 
 use super::coherence::{self, Conflict};
 use super::DerivedObligationCause;
-use super::IntercrateMode;
+use super::{IntercrateMode, TraitQueryMode};
 use super::project;
 use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey};
 use super::{PredicateObligation, TraitObligation, ObligationCause};
@@ -87,7 +87,12 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
     /// Controls whether or not to filter out negative impls when selecting.
     /// This is used in librustdoc to distinguish between the lack of an impl
     /// and a negative impl
-    allow_negative_impls: bool
+    allow_negative_impls: 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.
+    query_mode: TraitQueryMode,
 }
 
 #[derive(Clone, Debug)]
@@ -440,6 +445,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             intercrate: None,
             intercrate_ambiguity_causes: None,
             allow_negative_impls: false,
+            query_mode: TraitQueryMode::Standard,
         }
     }
 
@@ -452,6 +458,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             intercrate: Some(mode),
             intercrate_ambiguity_causes: None,
             allow_negative_impls: false,
+            query_mode: TraitQueryMode::Standard,
         }
     }
 
@@ -464,6 +471,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             intercrate: None,
             intercrate_ambiguity_causes: None,
             allow_negative_impls,
+            query_mode: TraitQueryMode::Standard,
+        }
+    }
+
+    pub fn with_query_mode(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
+                           query_mode: TraitQueryMode) -> SelectionContext<'cx, 'gcx, 'tcx> {
+        debug!("with_query_mode({:?})", query_mode);
+        SelectionContext {
+            infcx,
+            freshener: infcx.freshener(),
+            intercrate: None,
+            intercrate_ambiguity_causes: None,
+            allow_negative_impls: false,
+            query_mode,
         }
     }
 
@@ -548,17 +569,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
         let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
 
+        // `select` is currently only called in standard query mode
+        assert!(self.query_mode == TraitQueryMode::Standard);
+
         let candidate = match self.candidate_from_obligation(&stack) {
-            Err(SelectionError::Overflow(o)) =>
-                self.infcx().report_overflow_error(&o, true),
+            Err(SelectionError::Overflow(_)) =>
+                bug!("Overflow should be caught earlier in standard query mode"),
             Err(e) => { return Err(e); },
             Ok(None) => { return Ok(None); },
             Ok(Some(candidate)) => candidate
         };
 
         match self.confirm_candidate(obligation, candidate) {
-            Err(SelectionError::Overflow(o)) =>
-                self.infcx().report_overflow_error(&o, true),
+            Err(SelectionError::Overflow(_)) =>
+                bug!("Overflow should be caught earlier in standard query mode"),
             Err(e) => Err(e),
             Ok(candidate) => Ok(Some(candidate))
         }
@@ -582,10 +606,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         debug!("predicate_may_hold_fatal({:?})",
                obligation);
 
-        match self.evaluate_obligation_recursively(obligation) {
-            Ok(result) => result.may_apply(),
-            Err(OverflowError(o)) => self.infcx().report_overflow_error(&o, true)
-        }
+        // This fatal query is a stopgap that should only be used in standard mode,
+        // where we do not expect overflow to be propagated.
+        assert!(self.query_mode == TraitQueryMode::Standard);
+
+        self.evaluate_obligation_recursively(obligation)
+            .expect("Overflow should be caught earlier in standard query mode")
+            .may_apply()
     }
 
     /// Evaluates whether the obligation `obligation` can be satisfied and returns
@@ -1024,7 +1051,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         // not update) the cache.
         let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
         if stack.obligation.recursion_depth >= recursion_limit {
-            return Err(Overflow(stack.obligation.clone()));
+            match self.query_mode {
+                TraitQueryMode::Standard => {
+                    self.infcx().report_overflow_error(&stack.obligation, true);
+                },
+                TraitQueryMode::Canonical => {
+                    return Err(Overflow(stack.obligation.clone()));
+                },
+            }
         }
 
         // Check the cache. Note that we skolemize the trait-ref
diff --git a/src/librustc_traits/evaluate_obligation.rs b/src/librustc_traits/evaluate_obligation.rs
index f43733f4637..a9cf35c4d70 100644
--- a/src/librustc_traits/evaluate_obligation.rs
+++ b/src/librustc_traits/evaluate_obligation.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use rustc::traits::{EvaluationResult, Obligation, ObligationCause,
-                    OverflowError, SelectionContext};
+                    OverflowError, SelectionContext, TraitQueryMode};
 use rustc::traits::query::CanonicalPredicateGoal;
 use rustc::ty::{ParamEnvAnd, TyCtxt};
 use syntax::codemap::DUMMY_SP;
@@ -27,7 +27,7 @@ crate fn evaluate_obligation<'tcx>(
             _canonical_inference_vars,
         ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
 
-        let mut selcx = SelectionContext::new(&infcx);
+        let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical);
         let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
 
         match selcx.evaluate_obligation_recursively(&obligation) {