mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-12 18:07:40 +00:00
Introduce trait query mode and use it to set overflow error handling policy in traits::select
This commit is contained in:
parent
3dd26b8a3e
commit
e5535fc7dd
@ -74,6 +74,19 @@ pub enum IntercrateMode {
|
|||||||
Fixed
|
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
|
/// An `Obligation` represents some trait reference (e.g. `int:Eq`) for
|
||||||
/// which the vtable must be found. The process of finding a vtable is
|
/// which the vtable must be found. The process of finding a vtable is
|
||||||
/// called "resolving" the `Obligation`. This process consists of
|
/// called "resolving" the `Obligation`. This process consists of
|
||||||
|
@ -17,7 +17,7 @@ use self::EvaluationResult::*;
|
|||||||
|
|
||||||
use super::coherence::{self, Conflict};
|
use super::coherence::{self, Conflict};
|
||||||
use super::DerivedObligationCause;
|
use super::DerivedObligationCause;
|
||||||
use super::IntercrateMode;
|
use super::{IntercrateMode, TraitQueryMode};
|
||||||
use super::project;
|
use super::project;
|
||||||
use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey};
|
use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey};
|
||||||
use super::{PredicateObligation, TraitObligation, ObligationCause};
|
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.
|
/// Controls whether or not to filter out negative impls when selecting.
|
||||||
/// This is used in librustdoc to distinguish between the lack of an impl
|
/// This is used in librustdoc to distinguish between the lack of an impl
|
||||||
/// and a negative 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)]
|
#[derive(Clone, Debug)]
|
||||||
@ -440,6 +445,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||||||
intercrate: None,
|
intercrate: None,
|
||||||
intercrate_ambiguity_causes: None,
|
intercrate_ambiguity_causes: None,
|
||||||
allow_negative_impls: false,
|
allow_negative_impls: false,
|
||||||
|
query_mode: TraitQueryMode::Standard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,6 +458,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||||||
intercrate: Some(mode),
|
intercrate: Some(mode),
|
||||||
intercrate_ambiguity_causes: None,
|
intercrate_ambiguity_causes: None,
|
||||||
allow_negative_impls: false,
|
allow_negative_impls: false,
|
||||||
|
query_mode: TraitQueryMode::Standard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,6 +471,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||||||
intercrate: None,
|
intercrate: None,
|
||||||
intercrate_ambiguity_causes: None,
|
intercrate_ambiguity_causes: None,
|
||||||
allow_negative_impls,
|
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);
|
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) {
|
let candidate = match self.candidate_from_obligation(&stack) {
|
||||||
Err(SelectionError::Overflow(o)) =>
|
Err(SelectionError::Overflow(_)) =>
|
||||||
self.infcx().report_overflow_error(&o, true),
|
bug!("Overflow should be caught earlier in standard query mode"),
|
||||||
Err(e) => { return Err(e); },
|
Err(e) => { return Err(e); },
|
||||||
Ok(None) => { return Ok(None); },
|
Ok(None) => { return Ok(None); },
|
||||||
Ok(Some(candidate)) => candidate
|
Ok(Some(candidate)) => candidate
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.confirm_candidate(obligation, candidate) {
|
match self.confirm_candidate(obligation, candidate) {
|
||||||
Err(SelectionError::Overflow(o)) =>
|
Err(SelectionError::Overflow(_)) =>
|
||||||
self.infcx().report_overflow_error(&o, true),
|
bug!("Overflow should be caught earlier in standard query mode"),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
Ok(candidate) => Ok(Some(candidate))
|
Ok(candidate) => Ok(Some(candidate))
|
||||||
}
|
}
|
||||||
@ -582,10 +606,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||||||
debug!("predicate_may_hold_fatal({:?})",
|
debug!("predicate_may_hold_fatal({:?})",
|
||||||
obligation);
|
obligation);
|
||||||
|
|
||||||
match self.evaluate_obligation_recursively(obligation) {
|
// This fatal query is a stopgap that should only be used in standard mode,
|
||||||
Ok(result) => result.may_apply(),
|
// where we do not expect overflow to be propagated.
|
||||||
Err(OverflowError(o)) => self.infcx().report_overflow_error(&o, true)
|
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
|
/// 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.
|
// not update) the cache.
|
||||||
let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
|
let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
|
||||||
if stack.obligation.recursion_depth >= recursion_limit {
|
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
|
// Check the cache. Note that we skolemize the trait-ref
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use rustc::traits::{EvaluationResult, Obligation, ObligationCause,
|
use rustc::traits::{EvaluationResult, Obligation, ObligationCause,
|
||||||
OverflowError, SelectionContext};
|
OverflowError, SelectionContext, TraitQueryMode};
|
||||||
use rustc::traits::query::CanonicalPredicateGoal;
|
use rustc::traits::query::CanonicalPredicateGoal;
|
||||||
use rustc::ty::{ParamEnvAnd, TyCtxt};
|
use rustc::ty::{ParamEnvAnd, TyCtxt};
|
||||||
use syntax::codemap::DUMMY_SP;
|
use syntax::codemap::DUMMY_SP;
|
||||||
@ -27,7 +27,7 @@ crate fn evaluate_obligation<'tcx>(
|
|||||||
_canonical_inference_vars,
|
_canonical_inference_vars,
|
||||||
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
|
) = 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);
|
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
|
||||||
|
|
||||||
match selcx.evaluate_obligation_recursively(&obligation) {
|
match selcx.evaluate_obligation_recursively(&obligation) {
|
||||||
|
Loading…
Reference in New Issue
Block a user