rollup merge of #23580: nikomatsakis/pattern-and-overflow
This commit is contained in:
commit
bed77408df
11 changed files with 88 additions and 104 deletions
|
|
@ -12,6 +12,7 @@ use super::{
|
|||
FulfillmentError,
|
||||
FulfillmentErrorCode,
|
||||
MismatchedProjectionTypes,
|
||||
Obligation,
|
||||
ObligationCauseCode,
|
||||
OutputTypeParameterMismatch,
|
||||
PredicateObligation,
|
||||
|
|
@ -21,6 +22,7 @@ use super::{
|
|||
use fmt_macros::{Parser, Piece, Position};
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef, TraitRef};
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
use std::collections::HashMap;
|
||||
use syntax::codemap::{DUMMY_SP, Span};
|
||||
use syntax::attr::{AttributeMethods, AttrMetaMethods};
|
||||
|
|
@ -137,24 +139,36 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
report
|
||||
}
|
||||
|
||||
/// Reports that an overflow has occurred and halts compilation. We
|
||||
/// halt compilation unconditionally because it is important that
|
||||
/// overflows never be masked -- they basically represent computations
|
||||
/// whose result could not be truly determined and thus we can't say
|
||||
/// if the program type checks or not -- and they are unusual
|
||||
/// occurrences in any case.
|
||||
pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &Obligation<'tcx, T>)
|
||||
-> !
|
||||
where T: UserString<'tcx> + TypeFoldable<'tcx>
|
||||
{
|
||||
let predicate =
|
||||
infcx.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
|
||||
"overflow evaluating the requirement `{}`",
|
||||
predicate.user_string(infcx.tcx));
|
||||
|
||||
suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
|
||||
|
||||
note_obligation_cause(infcx, obligation);
|
||||
|
||||
infcx.tcx.sess.abort_if_errors();
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
error: &SelectionError<'tcx>)
|
||||
{
|
||||
match *error {
|
||||
SelectionError::Overflow => {
|
||||
// We could track the stack here more precisely if we wanted, I imagine.
|
||||
let predicate =
|
||||
infcx.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
|
||||
"overflow evaluating the requirement `{}`",
|
||||
predicate.user_string(infcx.tcx));
|
||||
|
||||
suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
|
||||
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
|
||||
SelectionError::Unimplemented => {
|
||||
match &obligation.cause.code {
|
||||
&ObligationCauseCode::CompareImplMethodObligation => {
|
||||
|
|
@ -309,8 +323,9 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>)
|
||||
fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &Obligation<'tcx, T>)
|
||||
where T: UserString<'tcx>
|
||||
{
|
||||
note_obligation_cause_code(infcx,
|
||||
&obligation.predicate,
|
||||
|
|
@ -318,10 +333,11 @@ fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
&obligation.cause.code);
|
||||
}
|
||||
|
||||
fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
predicate: &ty::Predicate<'tcx>,
|
||||
cause_span: Span,
|
||||
cause_code: &ObligationCauseCode<'tcx>)
|
||||
fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
predicate: &T,
|
||||
cause_span: Span,
|
||||
cause_code: &ObligationCauseCode<'tcx>)
|
||||
where T: UserString<'tcx>
|
||||
{
|
||||
let tcx = infcx.tcx;
|
||||
match *cause_code {
|
||||
|
|
|
|||
|
|
@ -23,9 +23,10 @@ use std::slice::Iter;
|
|||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
use util::ppaux::{Repr, UserString};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub use self::error_reporting::report_fulfillment_errors;
|
||||
pub use self::error_reporting::report_overflow_error;
|
||||
pub use self::error_reporting::suggest_new_overflow_limit;
|
||||
pub use self::coherence::orphan_check;
|
||||
pub use self::coherence::overlapping_impls;
|
||||
|
|
@ -151,7 +152,6 @@ pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
|
|||
#[derive(Clone,Debug)]
|
||||
pub enum SelectionError<'tcx> {
|
||||
Unimplemented,
|
||||
Overflow,
|
||||
OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>,
|
||||
ty::PolyTraitRef<'tcx>,
|
||||
ty::type_err<'tcx>),
|
||||
|
|
@ -327,16 +327,9 @@ pub fn evaluate_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
|||
let result = match fulfill_cx.select_all_or_error(infcx, typer) {
|
||||
Ok(()) => Ok(Some(())), // Success, we know it implements Copy.
|
||||
Err(errors) => {
|
||||
// Check if overflow occurred anywhere and propagate that.
|
||||
if errors.iter().any(
|
||||
|err| match err.code { CodeSelectionError(Overflow) => true, _ => false })
|
||||
{
|
||||
return Err(Overflow);
|
||||
}
|
||||
|
||||
// Otherwise, if there were any hard errors, propagate an
|
||||
// arbitrary one of those. If no hard errors at all,
|
||||
// report ambiguity.
|
||||
// If there were any hard errors, propagate an arbitrary
|
||||
// one of those. If no hard errors at all, report
|
||||
// ambiguity.
|
||||
let sel_error =
|
||||
errors.iter()
|
||||
.filter_map(|err| {
|
||||
|
|
@ -384,16 +377,8 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
|||
// soldering on, so just treat this like not implemented
|
||||
false
|
||||
}
|
||||
Err(Overflow) => {
|
||||
span_err!(infcx.tcx.sess, span, E0285,
|
||||
"overflow evaluating whether `{}` is `{}`",
|
||||
ty.user_string(infcx.tcx),
|
||||
bound.user_string(infcx.tcx));
|
||||
suggest_new_overflow_limit(infcx.tcx, span);
|
||||
false
|
||||
}
|
||||
Err(_) => {
|
||||
// other errors: not implemented.
|
||||
// errors: not implemented.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
@ -652,15 +637,6 @@ impl<'tcx> FulfillmentError<'tcx> {
|
|||
{
|
||||
FulfillmentError { obligation: obligation, code: code }
|
||||
}
|
||||
|
||||
pub fn is_overflow(&self) -> bool {
|
||||
match self.code {
|
||||
CodeAmbiguity => false,
|
||||
CodeSelectionError(Overflow) => true,
|
||||
CodeSelectionError(_) => false,
|
||||
CodeProjectionError(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TraitObligation<'tcx> {
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
//! Code for projecting associated types out of trait references.
|
||||
|
||||
use super::elaborate_predicates;
|
||||
use super::report_overflow_error;
|
||||
use super::Obligation;
|
||||
use super::ObligationCause;
|
||||
use super::Overflow;
|
||||
use super::PredicateObligation;
|
||||
use super::SelectionContext;
|
||||
use super::SelectionError;
|
||||
|
|
@ -442,7 +442,7 @@ fn project_type<'cx,'tcx>(
|
|||
let recursion_limit = selcx.tcx().sess.recursion_limit.get();
|
||||
if obligation.recursion_depth >= recursion_limit {
|
||||
debug!("project: overflow!");
|
||||
return Err(ProjectionTyError::TraitSelectionError(Overflow));
|
||||
report_overflow_error(selcx.infcx(), &obligation);
|
||||
}
|
||||
|
||||
let obligation_trait_ref =
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@ use super::DerivedObligationCause;
|
|||
use super::project;
|
||||
use super::project::{normalize_with_depth, Normalized};
|
||||
use super::{PredicateObligation, TraitObligation, ObligationCause};
|
||||
use super::{report_overflow_error};
|
||||
use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
|
||||
use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
|
||||
use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
|
||||
use super::{Selection};
|
||||
use super::{SelectionResult};
|
||||
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
|
||||
|
|
@ -561,10 +562,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// not update) the cache.
|
||||
let recursion_limit = self.infcx.tcx.sess.recursion_limit.get();
|
||||
if stack.obligation.recursion_depth >= recursion_limit {
|
||||
debug!("{} --> overflow (limit={})",
|
||||
stack.obligation.repr(self.tcx()),
|
||||
recursion_limit);
|
||||
return Err(Overflow)
|
||||
report_overflow_error(self.infcx(), &stack.obligation);
|
||||
}
|
||||
|
||||
// Check the cache. Note that we skolemize the trait-ref
|
||||
|
|
@ -2582,11 +2580,13 @@ impl<'o, 'tcx> Repr<'tcx> for TraitObligationStack<'o, 'tcx> {
|
|||
impl<'tcx> EvaluationResult<'tcx> {
|
||||
fn may_apply(&self) -> bool {
|
||||
match *self {
|
||||
EvaluatedToOk
|
||||
| EvaluatedToAmbig
|
||||
| EvaluatedToErr(Overflow)
|
||||
| EvaluatedToErr(OutputTypeParameterMismatch(..)) => true,
|
||||
EvaluatedToErr(Unimplemented) => false,
|
||||
EvaluatedToOk |
|
||||
EvaluatedToAmbig |
|
||||
EvaluatedToErr(OutputTypeParameterMismatch(..)) =>
|
||||
true,
|
||||
|
||||
EvaluatedToErr(Unimplemented) =>
|
||||
false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -514,9 +514,6 @@ impl<'tcx> Repr<'tcx> for super::VtableObjectData<'tcx> {
|
|||
impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
super::Overflow =>
|
||||
format!("Overflow"),
|
||||
|
||||
super::Unimplemented =>
|
||||
format!("Unimplemented"),
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue