Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor how we handle overflow and remove blanket Pattern impl #23580

Merged
merged 2 commits into from
Mar 24, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/libcollections/string.rs
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ use core::mem;
use core::ops::{self, Deref, Add, Index};
use core::ptr;
use core::slice;
use core::str::Pattern;
use unicode::str as unicode_str;
use unicode::str::Utf16Item;

@@ -765,6 +766,25 @@ impl<'a> Extend<&'a str> for String {
}
}

/// A convenience impl that delegates to the impl for `&str`
impl<'a, 'b> Pattern<'a> for &'b String {
type Searcher = <&'b str as Pattern<'a>>::Searcher;

fn into_searcher(self, haystack: &'a str) -> <&'b str as Pattern<'a>>::Searcher {
self[..].into_searcher(haystack)
}

#[inline]
fn is_contained_in(self, haystack: &'a str) -> bool {
self[..].is_contained_in(haystack)
}

#[inline]
fn is_prefix_of(self, haystack: &'a str) -> bool {
self[..].is_prefix_of(haystack)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq for String {
#[inline]
20 changes: 7 additions & 13 deletions src/libcore/str/pattern.rs
Original file line number Diff line number Diff line change
@@ -474,22 +474,16 @@ impl<'a, 'b> Pattern<'a> for &'b [char] {
s, CharEqPattern(s));
}

/// A convenience impl that delegates to the impl for `&str`
impl<'a, 'b> Pattern<'a> for &'b &'b str {
type Searcher = <&'b str as Pattern<'a>>::Searcher;
associated_items!(<&'b str as Pattern<'a>>::Searcher,
s, (*s));
}

/// Searches for chars that match the given predicate
impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool {
type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
s, CharEqPattern(s));
}

// Deref-forward impl

use ops::Deref;

/// Delegates to the next deref coercion of `Self` that implements `Pattern`
impl<'a, 'b, P: 'b + ?Sized, T: Deref<Target = P> + ?Sized> Pattern<'a> for &'b T
where &'b P: Pattern<'a>
{
type Searcher = <&'b P as Pattern<'a>>::Searcher;
associated_items!(<&'b P as Pattern<'a>>::Searcher,
s, (&**s));
}
2 changes: 0 additions & 2 deletions src/libcoretest/str.rs
Original file line number Diff line number Diff line change
@@ -13,9 +13,7 @@ fn test_pattern_deref_forward() {
let data = "aabcdaa";
assert!(data.contains("bcd"));
assert!(data.contains(&"bcd"));
assert!(data.contains(&&"bcd"));
assert!(data.contains(&"bcd".to_string()));
assert!(data.contains(&&"bcd".to_string()));
}

#[test]
54 changes: 35 additions & 19 deletions src/librustc/middle/traits/error_reporting.rs
Original file line number Diff line number Diff line change
@@ -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,19 +323,21 @@ 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,
obligation.cause.span,
&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 {
36 changes: 6 additions & 30 deletions src/librustc/middle/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -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> {
4 changes: 2 additions & 2 deletions src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
@@ -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 =
20 changes: 10 additions & 10 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
@@ -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,
}
}
}
3 changes: 0 additions & 3 deletions src/librustc/middle/traits/util.rs
Original file line number Diff line number Diff line change
@@ -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"),

21 changes: 7 additions & 14 deletions src/librustc_trans/trans/common.rs
Original file line number Diff line number Diff line change
@@ -1025,8 +1025,9 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// shallow result we are looking for -- that is, what specific impl.
let typer = NormalizingClosureTyper::new(tcx);
let mut selcx = traits::SelectionContext::new(&infcx, &typer);
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
trait_ref.to_poly_trait_predicate());
let obligation =
traits::Obligation::new(traits::ObligationCause::misc(span, ast::DUMMY_NODE_ID),
trait_ref.to_poly_trait_predicate());
let selection = match selcx.select(&obligation) {
Ok(Some(selection)) => selection,
Ok(None) => {
@@ -1081,7 +1082,7 @@ pub fn predicates_hold<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), predicate);
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &()).is_ok()
drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()).is_ok()
}

pub struct NormalizingClosureTyper<'a,'tcx:'a> {
@@ -1138,7 +1139,7 @@ pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
-> T
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
match drain_fulfillment_cx(span, infcx, fulfill_cx, result) {
match drain_fulfillment_cx(infcx, fulfill_cx, result) {
Ok(v) => v,
Err(errors) => {
infcx.tcx.sess.span_bug(
@@ -1156,8 +1157,7 @@ pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
/// inference variables that appear in `result` to be unified, and
/// hence we need to process those obligations to get the complete
/// picture of the type.
pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
infcx: &infer::InferCtxt<'a,'tcx>,
pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &infer::InferCtxt<'a,'tcx>,
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
result: &T)
-> StdResult<T,Vec<traits::FulfillmentError<'tcx>>>
@@ -1173,14 +1173,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
match fulfill_cx.select_all_or_error(infcx, &typer) {
Ok(()) => { }
Err(errors) => {
// We always want to surface any overflow errors, no matter what.
if errors.iter().all(|e| e.is_overflow()) {
infcx.tcx.sess.span_fatal(
span,
"reached the recursion limit during monomorphization");
} else {
return Err(errors);
}
return Err(errors);
}
}

3 changes: 0 additions & 3 deletions src/test/compile-fail/issue-18400.rs
Original file line number Diff line number Diff line change
@@ -33,7 +33,4 @@ fn main() {

0.contains(bits);
//~^ ERROR overflow
//~| ERROR overflow
//~| ERROR overflow
//~| ERROR mismatched types
}
9 changes: 1 addition & 8 deletions src/test/compile-fail/recursion_limit.rs
Original file line number Diff line number Diff line change
@@ -42,12 +42,5 @@ fn is_send<T:Send>() { }
fn main() {
is_send::<A>();
//~^ ERROR overflow evaluating
//~^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
//~^^^ NOTE required by `is_send`
//~^^^^ ERROR overflow evaluating
//~^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
//~^^^^^^ NOTE required by `is_send`
//~^^^^^^^ ERROR overflow evaluating
//~^^^^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
//~^^^^^^^^^ NOTE required by `is_send`
//~| NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
}