Skip to content

Commit 8bd8466

Browse files
committed
Refactor how we handle overflow so that it is a fatal error that aborts
compilation: this removes all the ungainly code that special cases overflow so that we can ensure it propagates.
1 parent 809a554 commit 8bd8466

File tree

8 files changed

+61
-89
lines changed

8 files changed

+61
-89
lines changed

src/librustc/middle/traits/error_reporting.rs

+35-19
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use super::{
1212
FulfillmentError,
1313
FulfillmentErrorCode,
1414
MismatchedProjectionTypes,
15+
Obligation,
1516
ObligationCauseCode,
1617
OutputTypeParameterMismatch,
1718
PredicateObligation,
@@ -21,6 +22,7 @@ use super::{
2122
use fmt_macros::{Parser, Piece, Position};
2223
use middle::infer::InferCtxt;
2324
use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef, TraitRef};
25+
use middle::ty_fold::TypeFoldable;
2426
use std::collections::HashMap;
2527
use syntax::codemap::{DUMMY_SP, Span};
2628
use syntax::attr::{AttributeMethods, AttrMetaMethods};
@@ -137,24 +139,36 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
137139
report
138140
}
139141

142+
/// Reports that an overflow has occurred and halts compilation. We
143+
/// halt compilation unconditionally because it is important that
144+
/// overflows never be masked -- they basically represent computations
145+
/// whose result could not be truly determined and thus we can't say
146+
/// if the program type checks or not -- and they are unusual
147+
/// occurrences in any case.
148+
pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
149+
obligation: &Obligation<'tcx, T>)
150+
-> !
151+
where T: UserString<'tcx> + TypeFoldable<'tcx>
152+
{
153+
let predicate =
154+
infcx.resolve_type_vars_if_possible(&obligation.predicate);
155+
span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
156+
"overflow evaluating the requirement `{}`",
157+
predicate.user_string(infcx.tcx));
158+
159+
suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
160+
161+
note_obligation_cause(infcx, obligation);
162+
163+
infcx.tcx.sess.abort_if_errors();
164+
unreachable!();
165+
}
166+
140167
pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
141168
obligation: &PredicateObligation<'tcx>,
142169
error: &SelectionError<'tcx>)
143170
{
144171
match *error {
145-
SelectionError::Overflow => {
146-
// We could track the stack here more precisely if we wanted, I imagine.
147-
let predicate =
148-
infcx.resolve_type_vars_if_possible(&obligation.predicate);
149-
span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
150-
"overflow evaluating the requirement `{}`",
151-
predicate.user_string(infcx.tcx));
152-
153-
suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
154-
155-
note_obligation_cause(infcx, obligation);
156-
}
157-
158172
SelectionError::Unimplemented => {
159173
match &obligation.cause.code {
160174
&ObligationCauseCode::CompareImplMethodObligation => {
@@ -309,19 +323,21 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
309323
}
310324
}
311325

312-
fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
313-
obligation: &PredicateObligation<'tcx>)
326+
fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
327+
obligation: &Obligation<'tcx, T>)
328+
where T: UserString<'tcx>
314329
{
315330
note_obligation_cause_code(infcx,
316331
&obligation.predicate,
317332
obligation.cause.span,
318333
&obligation.cause.code);
319334
}
320335

321-
fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
322-
predicate: &ty::Predicate<'tcx>,
323-
cause_span: Span,
324-
cause_code: &ObligationCauseCode<'tcx>)
336+
fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
337+
predicate: &T,
338+
cause_span: Span,
339+
cause_code: &ObligationCauseCode<'tcx>)
340+
where T: UserString<'tcx>
325341
{
326342
let tcx = infcx.tcx;
327343
match *cause_code {

src/librustc/middle/traits/mod.rs

+6-30
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ use std::slice::Iter;
2323
use std::rc::Rc;
2424
use syntax::ast;
2525
use syntax::codemap::{Span, DUMMY_SP};
26-
use util::ppaux::{Repr, UserString};
26+
use util::ppaux::Repr;
2727

2828
pub use self::error_reporting::report_fulfillment_errors;
29+
pub use self::error_reporting::report_overflow_error;
2930
pub use self::error_reporting::suggest_new_overflow_limit;
3031
pub use self::coherence::orphan_check;
3132
pub use self::coherence::overlapping_impls;
@@ -151,7 +152,6 @@ pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
151152
#[derive(Clone,Debug)]
152153
pub enum SelectionError<'tcx> {
153154
Unimplemented,
154-
Overflow,
155155
OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>,
156156
ty::PolyTraitRef<'tcx>,
157157
ty::type_err<'tcx>),
@@ -327,16 +327,9 @@ pub fn evaluate_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
327327
let result = match fulfill_cx.select_all_or_error(infcx, typer) {
328328
Ok(()) => Ok(Some(())), // Success, we know it implements Copy.
329329
Err(errors) => {
330-
// Check if overflow occurred anywhere and propagate that.
331-
if errors.iter().any(
332-
|err| match err.code { CodeSelectionError(Overflow) => true, _ => false })
333-
{
334-
return Err(Overflow);
335-
}
336-
337-
// Otherwise, if there were any hard errors, propagate an
338-
// arbitrary one of those. If no hard errors at all,
339-
// report ambiguity.
330+
// If there were any hard errors, propagate an arbitrary
331+
// one of those. If no hard errors at all, report
332+
// ambiguity.
340333
let sel_error =
341334
errors.iter()
342335
.filter_map(|err| {
@@ -384,16 +377,8 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
384377
// soldering on, so just treat this like not implemented
385378
false
386379
}
387-
Err(Overflow) => {
388-
span_err!(infcx.tcx.sess, span, E0285,
389-
"overflow evaluating whether `{}` is `{}`",
390-
ty.user_string(infcx.tcx),
391-
bound.user_string(infcx.tcx));
392-
suggest_new_overflow_limit(infcx.tcx, span);
393-
false
394-
}
395380
Err(_) => {
396-
// other errors: not implemented.
381+
// errors: not implemented.
397382
false
398383
}
399384
}
@@ -652,15 +637,6 @@ impl<'tcx> FulfillmentError<'tcx> {
652637
{
653638
FulfillmentError { obligation: obligation, code: code }
654639
}
655-
656-
pub fn is_overflow(&self) -> bool {
657-
match self.code {
658-
CodeAmbiguity => false,
659-
CodeSelectionError(Overflow) => true,
660-
CodeSelectionError(_) => false,
661-
CodeProjectionError(_) => false,
662-
}
663-
}
664640
}
665641

666642
impl<'tcx> TraitObligation<'tcx> {

src/librustc/middle/traits/project.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
//! Code for projecting associated types out of trait references.
1212
1313
use super::elaborate_predicates;
14+
use super::report_overflow_error;
1415
use super::Obligation;
1516
use super::ObligationCause;
16-
use super::Overflow;
1717
use super::PredicateObligation;
1818
use super::SelectionContext;
1919
use super::SelectionError;
@@ -442,7 +442,7 @@ fn project_type<'cx,'tcx>(
442442
let recursion_limit = selcx.tcx().sess.recursion_limit.get();
443443
if obligation.recursion_depth >= recursion_limit {
444444
debug!("project: overflow!");
445-
return Err(ProjectionTyError::TraitSelectionError(Overflow));
445+
report_overflow_error(selcx.infcx(), &obligation);
446446
}
447447

448448
let obligation_trait_ref =

src/librustc/middle/traits/select.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ use super::DerivedObligationCause;
2121
use super::project;
2222
use super::project::{normalize_with_depth, Normalized};
2323
use super::{PredicateObligation, TraitObligation, ObligationCause};
24+
use super::{report_overflow_error};
2425
use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
25-
use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
26+
use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
2627
use super::{Selection};
2728
use super::{SelectionResult};
2829
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
@@ -561,10 +562,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
561562
// not update) the cache.
562563
let recursion_limit = self.infcx.tcx.sess.recursion_limit.get();
563564
if stack.obligation.recursion_depth >= recursion_limit {
564-
debug!("{} --> overflow (limit={})",
565-
stack.obligation.repr(self.tcx()),
566-
recursion_limit);
567-
return Err(Overflow)
565+
report_overflow_error(self.infcx(), &stack.obligation);
568566
}
569567

570568
// Check the cache. Note that we skolemize the trait-ref
@@ -2582,11 +2580,13 @@ impl<'o, 'tcx> Repr<'tcx> for TraitObligationStack<'o, 'tcx> {
25822580
impl<'tcx> EvaluationResult<'tcx> {
25832581
fn may_apply(&self) -> bool {
25842582
match *self {
2585-
EvaluatedToOk
2586-
| EvaluatedToAmbig
2587-
| EvaluatedToErr(Overflow)
2588-
| EvaluatedToErr(OutputTypeParameterMismatch(..)) => true,
2589-
EvaluatedToErr(Unimplemented) => false,
2583+
EvaluatedToOk |
2584+
EvaluatedToAmbig |
2585+
EvaluatedToErr(OutputTypeParameterMismatch(..)) =>
2586+
true,
2587+
2588+
EvaluatedToErr(Unimplemented) =>
2589+
false,
25902590
}
25912591
}
25922592
}

src/librustc/middle/traits/util.rs

-3
Original file line numberDiff line numberDiff line change
@@ -514,9 +514,6 @@ impl<'tcx> Repr<'tcx> for super::VtableObjectData<'tcx> {
514514
impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> {
515515
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
516516
match *self {
517-
super::Overflow =>
518-
format!("Overflow"),
519-
520517
super::Unimplemented =>
521518
format!("Unimplemented"),
522519

src/librustc_trans/trans/common.rs

+7-14
Original file line numberDiff line numberDiff line change
@@ -1025,8 +1025,9 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
10251025
// shallow result we are looking for -- that is, what specific impl.
10261026
let typer = NormalizingClosureTyper::new(tcx);
10271027
let mut selcx = traits::SelectionContext::new(&infcx, &typer);
1028-
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
1029-
trait_ref.to_poly_trait_predicate());
1028+
let obligation =
1029+
traits::Obligation::new(traits::ObligationCause::misc(span, ast::DUMMY_NODE_ID),
1030+
trait_ref.to_poly_trait_predicate());
10301031
let selection = match selcx.select(&obligation) {
10311032
Ok(Some(selection)) => selection,
10321033
Ok(None) => {
@@ -1081,7 +1082,7 @@ pub fn predicates_hold<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
10811082
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), predicate);
10821083
fulfill_cx.register_predicate_obligation(&infcx, obligation);
10831084
}
1084-
drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &()).is_ok()
1085+
drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()).is_ok()
10851086
}
10861087

10871088
pub struct NormalizingClosureTyper<'a,'tcx:'a> {
@@ -1138,7 +1139,7 @@ pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
11381139
-> T
11391140
where T : TypeFoldable<'tcx> + Repr<'tcx>
11401141
{
1141-
match drain_fulfillment_cx(span, infcx, fulfill_cx, result) {
1142+
match drain_fulfillment_cx(infcx, fulfill_cx, result) {
11421143
Ok(v) => v,
11431144
Err(errors) => {
11441145
infcx.tcx.sess.span_bug(
@@ -1156,8 +1157,7 @@ pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
11561157
/// inference variables that appear in `result` to be unified, and
11571158
/// hence we need to process those obligations to get the complete
11581159
/// picture of the type.
1159-
pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
1160-
infcx: &infer::InferCtxt<'a,'tcx>,
1160+
pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &infer::InferCtxt<'a,'tcx>,
11611161
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
11621162
result: &T)
11631163
-> StdResult<T,Vec<traits::FulfillmentError<'tcx>>>
@@ -1173,14 +1173,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
11731173
match fulfill_cx.select_all_or_error(infcx, &typer) {
11741174
Ok(()) => { }
11751175
Err(errors) => {
1176-
// We always want to surface any overflow errors, no matter what.
1177-
if errors.iter().all(|e| e.is_overflow()) {
1178-
infcx.tcx.sess.span_fatal(
1179-
span,
1180-
"reached the recursion limit during monomorphization");
1181-
} else {
1182-
return Err(errors);
1183-
}
1176+
return Err(errors);
11841177
}
11851178
}
11861179

src/test/compile-fail/issue-18400.rs

-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,4 @@ fn main() {
3333

3434
0.contains(bits);
3535
//~^ ERROR overflow
36-
//~| ERROR overflow
37-
//~| ERROR overflow
38-
//~| ERROR mismatched types
3936
}

src/test/compile-fail/recursion_limit.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,5 @@ fn is_send<T:Send>() { }
4242
fn main() {
4343
is_send::<A>();
4444
//~^ ERROR overflow evaluating
45-
//~^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
46-
//~^^^ NOTE required by `is_send`
47-
//~^^^^ ERROR overflow evaluating
48-
//~^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
49-
//~^^^^^^ NOTE required by `is_send`
50-
//~^^^^^^^ ERROR overflow evaluating
51-
//~^^^^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
52-
//~^^^^^^^^^ NOTE required by `is_send`
45+
//~| NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
5346
}

0 commit comments

Comments
 (0)