Skip to content

Commit

Permalink
Introduce trait query mode and use it to set overflow error handling …
Browse files Browse the repository at this point in the history
…policy in traits::select
  • Loading branch information
aravind-pg committed Apr 27, 2018
1 parent 3dd26b8 commit e5535fc
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 13 deletions.
13 changes: 13 additions & 0 deletions src/librustc/traits/mod.rs
Expand Up @@ -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
Expand Down
56 changes: 45 additions & 11 deletions src/librustc/traits/select.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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,
}
}

Expand All @@ -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,
}
}

Expand All @@ -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,
}
}

Expand Down Expand Up @@ -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))
}
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_traits/evaluate_obligation.rs
Expand Up @@ -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;
Expand All @@ -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) {
Expand Down

0 comments on commit e5535fc

Please sign in to comment.