Skip to content

Commit e5535fc

Browse files
committed
Introduce trait query mode and use it to set overflow error handling policy in traits::select
1 parent 3dd26b8 commit e5535fc

File tree

3 files changed

+60
-13
lines changed

3 files changed

+60
-13
lines changed

src/librustc/traits/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,19 @@ pub enum IntercrateMode {
7474
Fixed
7575
}
7676

77+
// The mode that trait queries run in
78+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
79+
pub enum TraitQueryMode {
80+
// Standard/un-canonicalized queries get accurate
81+
// spans etc. passed in and hence can do reasonable
82+
// error reporting on their own.
83+
Standard,
84+
// Canonicalized queries get dummy spans and hence
85+
// must generally propagate errors to
86+
// pre-canonicalization callsites.
87+
Canonical,
88+
}
89+
7790
/// An `Obligation` represents some trait reference (e.g. `int:Eq`) for
7891
/// which the vtable must be found. The process of finding a vtable is
7992
/// called "resolving" the `Obligation`. This process consists of

src/librustc/traits/select.rs

+45-11
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use self::EvaluationResult::*;
1717

1818
use super::coherence::{self, Conflict};
1919
use super::DerivedObligationCause;
20-
use super::IntercrateMode;
20+
use super::{IntercrateMode, TraitQueryMode};
2121
use super::project;
2222
use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey};
2323
use super::{PredicateObligation, TraitObligation, ObligationCause};
@@ -87,7 +87,12 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
8787
/// Controls whether or not to filter out negative impls when selecting.
8888
/// This is used in librustdoc to distinguish between the lack of an impl
8989
/// and a negative impl
90-
allow_negative_impls: bool
90+
allow_negative_impls: bool,
91+
92+
/// The mode that trait queries run in, which informs our error handling
93+
/// policy. In essence, canonicalized queries need their errors propagated
94+
/// rather than immediately reported because we do not have accurate spans.
95+
query_mode: TraitQueryMode,
9196
}
9297

9398
#[derive(Clone, Debug)]
@@ -440,6 +445,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
440445
intercrate: None,
441446
intercrate_ambiguity_causes: None,
442447
allow_negative_impls: false,
448+
query_mode: TraitQueryMode::Standard,
443449
}
444450
}
445451

@@ -452,6 +458,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
452458
intercrate: Some(mode),
453459
intercrate_ambiguity_causes: None,
454460
allow_negative_impls: false,
461+
query_mode: TraitQueryMode::Standard,
455462
}
456463
}
457464

@@ -464,6 +471,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
464471
intercrate: None,
465472
intercrate_ambiguity_causes: None,
466473
allow_negative_impls,
474+
query_mode: TraitQueryMode::Standard,
475+
}
476+
}
477+
478+
pub fn with_query_mode(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
479+
query_mode: TraitQueryMode) -> SelectionContext<'cx, 'gcx, 'tcx> {
480+
debug!("with_query_mode({:?})", query_mode);
481+
SelectionContext {
482+
infcx,
483+
freshener: infcx.freshener(),
484+
intercrate: None,
485+
intercrate_ambiguity_causes: None,
486+
allow_negative_impls: false,
487+
query_mode,
467488
}
468489
}
469490

@@ -548,17 +569,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
548569

549570
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
550571

572+
// `select` is currently only called in standard query mode
573+
assert!(self.query_mode == TraitQueryMode::Standard);
574+
551575
let candidate = match self.candidate_from_obligation(&stack) {
552-
Err(SelectionError::Overflow(o)) =>
553-
self.infcx().report_overflow_error(&o, true),
576+
Err(SelectionError::Overflow(_)) =>
577+
bug!("Overflow should be caught earlier in standard query mode"),
554578
Err(e) => { return Err(e); },
555579
Ok(None) => { return Ok(None); },
556580
Ok(Some(candidate)) => candidate
557581
};
558582

559583
match self.confirm_candidate(obligation, candidate) {
560-
Err(SelectionError::Overflow(o)) =>
561-
self.infcx().report_overflow_error(&o, true),
584+
Err(SelectionError::Overflow(_)) =>
585+
bug!("Overflow should be caught earlier in standard query mode"),
562586
Err(e) => Err(e),
563587
Ok(candidate) => Ok(Some(candidate))
564588
}
@@ -582,10 +606,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
582606
debug!("predicate_may_hold_fatal({:?})",
583607
obligation);
584608

585-
match self.evaluate_obligation_recursively(obligation) {
586-
Ok(result) => result.may_apply(),
587-
Err(OverflowError(o)) => self.infcx().report_overflow_error(&o, true)
588-
}
609+
// This fatal query is a stopgap that should only be used in standard mode,
610+
// where we do not expect overflow to be propagated.
611+
assert!(self.query_mode == TraitQueryMode::Standard);
612+
613+
self.evaluate_obligation_recursively(obligation)
614+
.expect("Overflow should be caught earlier in standard query mode")
615+
.may_apply()
589616
}
590617

591618
/// Evaluates whether the obligation `obligation` can be satisfied and returns
@@ -1024,7 +1051,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
10241051
// not update) the cache.
10251052
let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
10261053
if stack.obligation.recursion_depth >= recursion_limit {
1027-
return Err(Overflow(stack.obligation.clone()));
1054+
match self.query_mode {
1055+
TraitQueryMode::Standard => {
1056+
self.infcx().report_overflow_error(&stack.obligation, true);
1057+
},
1058+
TraitQueryMode::Canonical => {
1059+
return Err(Overflow(stack.obligation.clone()));
1060+
},
1061+
}
10281062
}
10291063

10301064
// Check the cache. Note that we skolemize the trait-ref

src/librustc_traits/evaluate_obligation.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use rustc::traits::{EvaluationResult, Obligation, ObligationCause,
12-
OverflowError, SelectionContext};
12+
OverflowError, SelectionContext, TraitQueryMode};
1313
use rustc::traits::query::CanonicalPredicateGoal;
1414
use rustc::ty::{ParamEnvAnd, TyCtxt};
1515
use syntax::codemap::DUMMY_SP;
@@ -27,7 +27,7 @@ crate fn evaluate_obligation<'tcx>(
2727
_canonical_inference_vars,
2828
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
2929

30-
let mut selcx = SelectionContext::new(&infcx);
30+
let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical);
3131
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
3232

3333
match selcx.evaluate_obligation_recursively(&obligation) {

0 commit comments

Comments
 (0)