This is slightly hacky and hopefully only a somewhat temporary solution.
use infer::InferCtxt;
use infer::canonical::{Canonical, Canonicalize};
-use traits::{EvaluationResult, PredicateObligation};
+use traits::{EvaluationResult, PredicateObligation, SelectionContext,
+ TraitQueryMode, OverflowError};
use traits::query::CanonicalPredicateGoal;
use ty::{ParamEnvAnd, Predicate, TyCtxt};
&self,
obligation: &PredicateObligation<'tcx>,
) -> bool {
- let (c_pred, _) =
- self.canonicalize_query(&obligation.param_env.and(obligation.predicate));
-
- self.tcx.global_tcx().evaluate_obligation(c_pred).may_apply()
+ self.evaluate_obligation(obligation).may_apply()
}
/// Evaluates whether the predicate can be satisfied in the given
&self,
obligation: &PredicateObligation<'tcx>,
) -> bool {
+ self.evaluate_obligation(obligation) == EvaluationResult::EvaluatedToOk
+ }
+
+ // Helper function that canonicalizes and runs the query, as well as handles
+ // overflow.
+ fn evaluate_obligation(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> EvaluationResult {
let (c_pred, _) =
self.canonicalize_query(&obligation.param_env.and(obligation.predicate));
-
- self.tcx.global_tcx().evaluate_obligation(c_pred) ==
- EvaluationResult::EvaluatedToOk
+ // Run canonical query. If overflow occurs, rerun from scratch but this time
+ // in standard trait query mode so that overflow is handled appropriately
+ // within `SelectionContext`.
+ match self.tcx.global_tcx().evaluate_obligation(c_pred) {
+ Ok(result) => result,
+ Err(OverflowError) => {
+ let mut selcx =
+ SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
+ selcx.evaluate_obligation_recursively(obligation)
+ .expect("Overflow should be caught earlier in standard query mode")
+ }
+ }
}
}
/// Indicates that trait evaluation caused overflow.
pub struct OverflowError;
+impl_stable_hash_for!(struct OverflowError { });
+
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
fn from(OverflowError: OverflowError) -> SelectionError<'tcx> {
SelectionError::Overflow
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) =>
- bug!("Overflow should be caught earlier in standard query mode"),
+ 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(e) => { return Err(e); },
Ok(None) => { return Ok(None); },
Ok(Some(candidate)) => candidate
};
match self.confirm_candidate(obligation, candidate) {
- Err(SelectionError::Overflow) =>
- bug!("Overflow should be caught earlier in standard query mode"),
+ Err(SelectionError::Overflow) => {
+ assert!(self.query_mode == TraitQueryMode::Canonical);
+ return Err(SelectionError::Overflow);
+ },
Err(e) => Err(e),
Ok(candidate) => Ok(Some(candidate))
}
/// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
/// `infcx.predicate_must_hold()` instead.
- [] fn evaluate_obligation:
- EvaluateObligation(CanonicalPredicateGoal<'tcx>) -> traits::EvaluationResult,
+ [] fn evaluate_obligation: EvaluateObligation(
+ CanonicalPredicateGoal<'tcx>
+ ) -> Result<traits::EvaluationResult, traits::OverflowError>,
[] fn substitute_normalize_and_test_predicates:
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
crate fn evaluate_obligation<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
goal: CanonicalPredicateGoal<'tcx>,
-) -> EvaluationResult {
+) -> Result<EvaluationResult, OverflowError> {
tcx.infer_ctxt().enter(|ref infcx| {
let (
ParamEnvAnd {
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) {
- Ok(result) => result,
- Err(OverflowError) => {
- infcx.report_overflow_error(&obligation, true)
- }
- }
+ selcx.evaluate_obligation_recursively(&obligation)
})
}