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
Show file tree
Hide file tree
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
Expand Up @@ -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;

Expand Down Expand Up @@ -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]
Expand Down
20 changes: 7 additions & 13 deletions src/libcore/str/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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]
Expand Down
54 changes: 35 additions & 19 deletions src/librustc/middle/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use super::{
FulfillmentError,
FulfillmentErrorCode,
MismatchedProjectionTypes,
Obligation,
ObligationCauseCode,
OutputTypeParameterMismatch,
PredicateObligation,
Expand All @@ -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};
Expand Down Expand Up @@ -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 => {
Expand Down Expand Up @@ -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 {
Expand Down
36 changes: 6 additions & 30 deletions src/librustc/middle/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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>),
Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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
}
}
Expand Down Expand Up @@ -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> {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 =
Expand Down
20 changes: 10 additions & 10 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
}
}
}
Expand Down
3 changes: 0 additions & 3 deletions src/librustc/middle/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),

Expand Down
21 changes: 7 additions & 14 deletions src/librustc_trans/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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(
Expand All @@ -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>>>
Expand All @@ -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);
}
}

Expand Down
3 changes: 0 additions & 3 deletions src/test/compile-fail/issue-18400.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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
}