Skip to content

Commit d5b2e90

Browse files
committed
Retry canonical trait query in standard mode if overflow occurs
This is slightly hacky and hopefully only a somewhat temporary solution.
1 parent 5cb0372 commit d5b2e90

File tree

4 files changed

+41
-24
lines changed

4 files changed

+41
-24
lines changed

src/librustc/traits/query/evaluate_obligation.rs

+24-8
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010

1111
use infer::InferCtxt;
1212
use infer::canonical::{Canonical, Canonicalize};
13-
use traits::{EvaluationResult, PredicateObligation};
13+
use traits::{EvaluationResult, PredicateObligation, SelectionContext,
14+
TraitQueryMode, OverflowError};
1415
use traits::query::CanonicalPredicateGoal;
1516
use ty::{ParamEnvAnd, Predicate, TyCtxt};
1617

@@ -21,10 +22,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
2122
&self,
2223
obligation: &PredicateObligation<'tcx>,
2324
) -> bool {
24-
let (c_pred, _) =
25-
self.canonicalize_query(&obligation.param_env.and(obligation.predicate));
26-
27-
self.tcx.global_tcx().evaluate_obligation(c_pred).may_apply()
25+
self.evaluate_obligation(obligation).may_apply()
2826
}
2927

3028
/// Evaluates whether the predicate can be satisfied in the given
@@ -34,11 +32,29 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
3432
&self,
3533
obligation: &PredicateObligation<'tcx>,
3634
) -> bool {
35+
self.evaluate_obligation(obligation) == EvaluationResult::EvaluatedToOk
36+
}
37+
38+
// Helper function that canonicalizes and runs the query, as well as handles
39+
// overflow.
40+
fn evaluate_obligation(
41+
&self,
42+
obligation: &PredicateObligation<'tcx>,
43+
) -> EvaluationResult {
3744
let (c_pred, _) =
3845
self.canonicalize_query(&obligation.param_env.and(obligation.predicate));
39-
40-
self.tcx.global_tcx().evaluate_obligation(c_pred) ==
41-
EvaluationResult::EvaluatedToOk
46+
// Run canonical query. If overflow occurs, rerun from scratch but this time
47+
// in standard trait query mode so that overflow is handled appropriately
48+
// within `SelectionContext`.
49+
match self.tcx.global_tcx().evaluate_obligation(c_pred) {
50+
Ok(result) => result,
51+
Err(OverflowError) => {
52+
let mut selcx =
53+
SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
54+
selcx.evaluate_obligation_recursively(obligation)
55+
.expect("Overflow should be caught earlier in standard query mode")
56+
}
57+
}
4258
}
4359
}
4460

src/librustc/traits/select.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,8 @@ impl_stable_hash_for!(enum self::EvaluationResult {
425425
/// Indicates that trait evaluation caused overflow.
426426
pub struct OverflowError;
427427

428+
impl_stable_hash_for!(struct OverflowError { });
429+
428430
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
429431
fn from(OverflowError: OverflowError) -> SelectionError<'tcx> {
430432
SelectionError::Overflow
@@ -568,20 +570,23 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
568570

569571
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
570572

571-
// `select` is currently only called in standard query mode
572-
assert!(self.query_mode == TraitQueryMode::Standard);
573-
574573
let candidate = match self.candidate_from_obligation(&stack) {
575-
Err(SelectionError::Overflow) =>
576-
bug!("Overflow should be caught earlier in standard query mode"),
574+
Err(SelectionError::Overflow) => {
575+
// In standard mode, overflow must have been caught and reported
576+
// earlier.
577+
assert!(self.query_mode == TraitQueryMode::Canonical);
578+
return Err(SelectionError::Overflow);
579+
},
577580
Err(e) => { return Err(e); },
578581
Ok(None) => { return Ok(None); },
579582
Ok(Some(candidate)) => candidate
580583
};
581584

582585
match self.confirm_candidate(obligation, candidate) {
583-
Err(SelectionError::Overflow) =>
584-
bug!("Overflow should be caught earlier in standard query mode"),
586+
Err(SelectionError::Overflow) => {
587+
assert!(self.query_mode == TraitQueryMode::Canonical);
588+
return Err(SelectionError::Overflow);
589+
},
585590
Err(e) => Err(e),
586591
Ok(candidate) => Ok(Some(candidate))
587592
}

src/librustc/ty/maps/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,9 @@ define_maps! { <'tcx>
436436

437437
/// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
438438
/// `infcx.predicate_must_hold()` instead.
439-
[] fn evaluate_obligation:
440-
EvaluateObligation(CanonicalPredicateGoal<'tcx>) -> traits::EvaluationResult,
439+
[] fn evaluate_obligation: EvaluateObligation(
440+
CanonicalPredicateGoal<'tcx>
441+
) -> Result<traits::EvaluationResult, traits::OverflowError>,
441442

442443
[] fn substitute_normalize_and_test_predicates:
443444
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,

src/librustc_traits/evaluate_obligation.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use syntax::codemap::DUMMY_SP;
1717
crate fn evaluate_obligation<'tcx>(
1818
tcx: TyCtxt<'_, 'tcx, 'tcx>,
1919
goal: CanonicalPredicateGoal<'tcx>,
20-
) -> EvaluationResult {
20+
) -> Result<EvaluationResult, OverflowError> {
2121
tcx.infer_ctxt().enter(|ref infcx| {
2222
let (
2323
ParamEnvAnd {
@@ -30,11 +30,6 @@ crate fn evaluate_obligation<'tcx>(
3030
let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical);
3131
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
3232

33-
match selcx.evaluate_obligation_recursively(&obligation) {
34-
Ok(result) => result,
35-
Err(OverflowError) => {
36-
infcx.report_overflow_error(&obligation, true)
37-
}
38-
}
33+
selcx.evaluate_obligation_recursively(&obligation)
3934
})
4035
}

0 commit comments

Comments
 (0)