diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 663746ac2dd3..44eceb1f213a 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -239,8 +239,7 @@ pub trait ErrorReporting<'tcx> { fn report_generic_bound_failure(&self, origin: SubregionOrigin<'tcx>, kind: GenericKind<'tcx>, - sub: Region, - sups: Vec); + sub: Region); fn report_sub_sup_conflict(&self, var_origin: RegionVariableOrigin, @@ -292,8 +291,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { self.report_concrete_failure(origin, sub, sup); } - GenericBoundFailure(kind, param_ty, sub, sups) => { - self.report_generic_bound_failure(kind, param_ty, sub, sups); + GenericBoundFailure(kind, param_ty, sub) => { + self.report_generic_bound_failure(kind, param_ty, sub); } SubSupConflict(var_origin, @@ -527,14 +526,18 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn report_generic_bound_failure(&self, origin: SubregionOrigin<'tcx>, bound_kind: GenericKind<'tcx>, - sub: Region, - _sups: Vec) + sub: Region) { // FIXME: it would be better to report the first error message // with the span of the parameter itself, rather than the span // where the error was detected. But that span is not readily // accessible. + let is_warning = match origin { + infer::RFC1214Subregion(_) => true, + _ => false, + }; + let labeled_user_string = match bound_kind { GenericKind::Param(ref p) => format!("the parameter type `{}`", p), @@ -545,7 +548,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { match sub { ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { // Does the required lifetime have a nice name we can print? - span_err!(self.tcx.sess, origin.span(), E0309, + span_err_or_warn!( + is_warning, self.tcx.sess, origin.span(), E0309, "{} may not live long enough", labeled_user_string); self.tcx.sess.fileline_help( origin.span(), @@ -557,7 +561,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { ty::ReStatic => { // Does the required lifetime have a nice name we can print? - span_err!(self.tcx.sess, origin.span(), E0310, + span_err_or_warn!( + is_warning, self.tcx.sess, origin.span(), E0310, "{} may not live long enough", labeled_user_string); self.tcx.sess.fileline_help( origin.span(), @@ -568,9 +573,10 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { _ => { // If not, be less specific. - span_err!(self.tcx.sess, origin.span(), E0311, - "{} may not live long enough", - labeled_user_string); + span_err_or_warn!( + is_warning, self.tcx.sess, origin.span(), E0311, + "{} may not live long enough", + labeled_user_string); self.tcx.sess.fileline_help( origin.span(), &format!( @@ -583,6 +589,10 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { } } + if is_warning { + self.tcx.sess.note_rfc_1214(origin.span()); + } + self.note_region_origin(&origin); } @@ -591,6 +601,13 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { sub: Region, sup: Region) { match origin { + infer::RFC1214Subregion(ref suborigin) => { + // Ideally, this would be a warning, but it doesn't + // seem to come up in practice, since the changes from + // RFC1214 mostly trigger errors in type definitions + // that don't wind up coming down this path. + self.report_concrete_failure((**suborigin).clone(), sub, sup); + } infer::Subtype(trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); self.report_and_explain_type_error(trace, &terr); @@ -819,6 +836,23 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { sup, ""); } + infer::ParameterInScope(_, span) => { + self.tcx.sess.span_err( + span, + &format!("type/lifetime parameter not in scope here")); + self.tcx.note_and_explain_region( + "the parameter is only valid for ", + sub, + ""); + } + infer::DataBorrowed(ty, span) => { + self.tcx.sess.span_err( + span, + &format!("a value of type `{}` is borrowed for too long", + self.ty_to_string(ty))); + self.tcx.note_and_explain_region("the type is valid for ", sub, ""); + self.tcx.note_and_explain_region("but the borrow lasts for ", sup, ""); + } infer::ReferenceOutlivesReferent(ty, span) => { self.tcx.sess.span_err( span, @@ -1567,6 +1601,9 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) { match *origin { + infer::RFC1214Subregion(ref suborigin) => { + self.note_region_origin(suborigin); + } infer::Subtype(ref trace) => { let desc = match trace.origin { infer::Misc(_) => { @@ -1714,6 +1751,17 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { span, "...so that variable is valid at time of its declaration"); } + infer::ParameterInScope(_, span) => { + self.tcx.sess.span_note( + span, + &format!("...so that a type/lifetime parameter is in scope here")); + } + infer::DataBorrowed(ty, span) => { + self.tcx.sess.span_note( + span, + &format!("...so that the type `{}` is not borrowed for too long", + self.ty_to_string(ty))); + } infer::ReferenceOutlivesReferent(ty, span) => { self.tcx.sess.span_note( span, diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index f63154af7242..da3749979b60 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -35,6 +35,7 @@ use middle::ty_relate::{Relate, RelateResult, TypeRelation}; use rustc_data_structures::unify::{self, UnificationTable}; use std::cell::{RefCell, Ref}; use std::fmt; +use std::rc::Rc; use syntax::ast; use syntax::codemap; use syntax::codemap::{Span, DUMMY_SP}; @@ -188,6 +189,8 @@ pub struct TypeTrace<'tcx> { /// See `error_reporting.rs` for more details #[derive(Clone, Debug)] pub enum SubregionOrigin<'tcx> { + RFC1214Subregion(Rc>), + // Arose from a subtyping relation Subtype(TypeTrace<'tcx>), @@ -229,9 +232,15 @@ pub enum SubregionOrigin<'tcx> { // Creating a pointer `b` to contents of an upvar ReborrowUpvar(Span, ty::UpvarId), + // Data with type `Ty<'tcx>` was borrowed + DataBorrowed(Ty<'tcx>, Span), + // (&'a &'b T) where a >= b ReferenceOutlivesReferent(Ty<'tcx>, Span), + // Type or region parameters must be in scope. + ParameterInScope(ParameterOrigin, Span), + // The type T of an expression E must outlive the lifetime for E. ExprTypeIsNotInScope(Ty<'tcx>, Span), @@ -260,6 +269,15 @@ pub enum SubregionOrigin<'tcx> { SafeDestructor(Span), } +/// Places that type/region parameters can appear. +#[derive(Clone, Copy, Debug)] +pub enum ParameterOrigin { + Path, // foo::bar + MethodCall, // foo.bar() <-- parameters on impl providing bar() + OverloadedOperator, // a + b when overloaded + OverloadedDeref, // *a when overloaded +} + /// Times when we replace late-bound regions with variables: #[derive(Clone, Copy, Debug)] pub enum LateBoundRegionConversionTime { @@ -1565,6 +1583,7 @@ impl TypeOrigin { impl<'tcx> SubregionOrigin<'tcx> { pub fn span(&self) -> Span { match *self { + RFC1214Subregion(ref a) => a.span(), Subtype(ref a) => a.span(), InfStackClosure(a) => a, InvokeClosure(a) => a, @@ -1577,7 +1596,9 @@ impl<'tcx> SubregionOrigin<'tcx> { RelateDefaultParamBound(a, _) => a, Reborrow(a) => a, ReborrowUpvar(a, _) => a, + DataBorrowed(_, a) => a, ReferenceOutlivesReferent(_, a) => a, + ParameterInScope(_, a) => a, ExprTypeIsNotInScope(_, a) => a, BindingTypeIsNotValidAtDecl(a) => a, CallRcvr(a) => a, diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 1f79db9e5232..fb2db5089c97 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -25,11 +25,12 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use middle::infer::InferCtxt; -use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef}; +use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef, Ty}; use middle::ty_fold::TypeFoldable; use std::collections::HashMap; use std::fmt; use syntax::codemap::Span; +use syntax::ast; use syntax::attr::{AttributeMethods, AttrMetaMethods}; pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, @@ -54,22 +55,28 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } } +fn is_warning(obligation: &Obligation) -> bool { + obligation.cause.code.is_rfc1214() +} + pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, obligation: &PredicateObligation<'tcx>, error: &MismatchedProjectionTypes<'tcx>) { let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate); + // The TyError created by normalize_to_error can end up being unified // into all obligations: for example, if our obligation is something // like `$X = <() as Foo<$X>>::Out` and () does not implement Foo<_>, // then $X will be unified with TyError, but the error still needs to be // reported. if !infcx.tcx.sess.has_errors() || !predicate.references_error() { - span_err!(infcx.tcx.sess, obligation.cause.span, E0271, - "type mismatch resolving `{}`: {}", - predicate, - error.err); + span_err_or_warn!( + is_warning(obligation), infcx.tcx.sess, obligation.cause.span, E0271, + "type mismatch resolving `{}`: {}", + predicate, + error.err); note_obligation_cause(infcx, obligation); } } @@ -173,66 +180,93 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>) { + let is_warning = is_warning(obligation); match *error { SelectionError::Unimplemented => { - match &obligation.cause.code { - &ObligationCauseCode::CompareImplMethodObligation => { - span_err!(infcx.tcx.sess, obligation.cause.span, E0276, - "the requirement `{}` appears on the impl \ - method but not on the corresponding trait method", - obligation.predicate);; - } - _ => { - match obligation.predicate { - ty::Predicate::Trait(ref trait_predicate) => { - let trait_predicate = - infcx.resolve_type_vars_if_possible(trait_predicate); + if let ObligationCauseCode::CompareImplMethodObligation = obligation.cause.code { + span_err_or_warn!( + is_warning, infcx.tcx.sess, obligation.cause.span, E0276, + "the requirement `{}` appears on the impl \ + method but not on the corresponding trait method", + obligation.predicate);; + } else { + match obligation.predicate { + ty::Predicate::Trait(ref trait_predicate) => { + let trait_predicate = + infcx.resolve_type_vars_if_possible(trait_predicate); - if !infcx.tcx.sess.has_errors() || - !trait_predicate.references_error() { - let trait_ref = trait_predicate.to_poly_trait_ref(); - span_err!(infcx.tcx.sess, obligation.cause.span, E0277, - "the trait `{}` is not implemented for the type `{}`", - trait_ref, - trait_ref.self_ty()); - // Check if it has a custom "#[rustc_on_unimplemented]" - // error message, report with that message if it does - let custom_note = report_on_unimplemented(infcx, &trait_ref.0, - obligation.cause.span); - if let Some(s) = custom_note { - infcx.tcx.sess.span_note(obligation.cause.span, - &s); - } + if !infcx.tcx.sess.has_errors() || !trait_predicate.references_error() { + let trait_ref = trait_predicate.to_poly_trait_ref(); + span_err_or_warn!( + is_warning, infcx.tcx.sess, obligation.cause.span, E0277, + "the trait `{}` is not implemented for the type `{}`", + trait_ref, trait_ref.self_ty()); + + // Check if it has a custom "#[rustc_on_unimplemented]" + // error message, report with that message if it does + let custom_note = report_on_unimplemented(infcx, &trait_ref.0, + obligation.cause.span); + if is_warning { + note_obligation_cause(infcx, obligation); + } else if let Some(s) = custom_note { + infcx.tcx.sess.span_note(obligation.cause.span, &s); + } else { + note_obligation_cause(infcx, obligation); } } + } - ty::Predicate::Equate(ref predicate) => { - let predicate = infcx.resolve_type_vars_if_possible(predicate); - let err = infcx.equality_predicate(obligation.cause.span, - &predicate).err().unwrap(); - span_err!(infcx.tcx.sess, obligation.cause.span, E0278, - "the requirement `{}` is not satisfied (`{}`)", - predicate, - err); - } + ty::Predicate::Equate(ref predicate) => { + let predicate = infcx.resolve_type_vars_if_possible(predicate); + let err = infcx.equality_predicate(obligation.cause.span, + &predicate).err().unwrap(); + span_err_or_warn!( + is_warning, infcx.tcx.sess, obligation.cause.span, E0278, + "the requirement `{}` is not satisfied (`{}`)", + predicate, + err); + note_obligation_cause(infcx, obligation); + } - ty::Predicate::RegionOutlives(ref predicate) => { - let predicate = infcx.resolve_type_vars_if_possible(predicate); - let err = infcx.region_outlives_predicate(obligation.cause.span, - &predicate).err().unwrap(); - span_err!(infcx.tcx.sess, obligation.cause.span, E0279, - "the requirement `{}` is not satisfied (`{}`)", - predicate, - err); - } + ty::Predicate::RegionOutlives(ref predicate) => { + let predicate = infcx.resolve_type_vars_if_possible(predicate); + let err = infcx.region_outlives_predicate(obligation.cause.span, + &predicate).err().unwrap(); + span_err_or_warn!( + is_warning, infcx.tcx.sess, obligation.cause.span, E0279, + "the requirement `{}` is not satisfied (`{}`)", + predicate, + err); + note_obligation_cause(infcx, obligation); + } - ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { - let predicate = - infcx.resolve_type_vars_if_possible(&obligation.predicate); - span_err!(infcx.tcx.sess, obligation.cause.span, E0280, - "the requirement `{}` is not satisfied", - predicate); - } + ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { + let predicate = + infcx.resolve_type_vars_if_possible(&obligation.predicate); + span_err_or_warn!( + is_warning, infcx.tcx.sess, obligation.cause.span, E0280, + "the requirement `{}` is not satisfied", + predicate); + note_obligation_cause(infcx, obligation); + } + + ty::Predicate::ObjectSafe(trait_def_id) => { + report_object_safety_error(infcx.tcx, + obligation.cause.span, + trait_def_id, + is_warning); + note_obligation_cause(infcx, obligation); + } + + ty::Predicate::WellFormed(ty) => { + // WF predicates cannot themselves make + // errors. They can only block due to + // ambiguity; otherwise, they always + // degenerate into other obligations + // (which may fail). + infcx.tcx.sess.span_bug( + obligation.cause.span, + &format!("WF predicate not satisfied for {:?}", ty)); } } } @@ -242,62 +276,73 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref); let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref); if !actual_trait_ref.self_ty().references_error() { - span_err!(infcx.tcx.sess, obligation.cause.span, E0281, - "type mismatch: the type `{}` implements the trait `{}`, \ - but the trait `{}` is required ({})", - expected_trait_ref.self_ty(), - expected_trait_ref, - actual_trait_ref, - e); - note_obligation_cause(infcx, obligation); + span_err_or_warn!( + is_warning, infcx.tcx.sess, obligation.cause.span, E0281, + "type mismatch: the type `{}` implements the trait `{}`, \ + but the trait `{}` is required ({})", + expected_trait_ref.self_ty(), + expected_trait_ref, + actual_trait_ref, + e); + note_obligation_cause(infcx, obligation); } } TraitNotObjectSafe(did) => { - span_err!(infcx.tcx.sess, obligation.cause.span, E0038, - "cannot convert to a trait object because trait `{}` is not object-safe", - infcx.tcx.item_path_str(did)); + report_object_safety_error(infcx.tcx, obligation.cause.span, did, is_warning); + note_obligation_cause(infcx, obligation); + } + } +} - for violation in object_safety_violations(infcx.tcx, did) { - match violation { - ObjectSafetyViolation::SizedSelf => { - infcx.tcx.sess.span_note( - obligation.cause.span, - "the trait cannot require that `Self : Sized`"); - } +pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>, + span: Span, + trait_def_id: ast::DefId, + is_warning: bool) +{ + span_err_or_warn!( + is_warning, tcx.sess, span, E0038, + "the trait `{}` cannot be made into an object", + tcx.item_path_str(trait_def_id)); - ObjectSafetyViolation::SupertraitSelf => { - infcx.tcx.sess.span_note( - obligation.cause.span, - "the trait cannot use `Self` as a type parameter \ - in the supertrait listing"); - } + for violation in object_safety_violations(tcx, trait_def_id) { + match violation { + ObjectSafetyViolation::SizedSelf => { + tcx.sess.span_note( + span, + "the trait cannot require that `Self : Sized`"); + } - ObjectSafetyViolation::Method(method, - MethodViolationCode::StaticMethod) => { - infcx.tcx.sess.span_note( - obligation.cause.span, - &format!("method `{}` has no receiver", - method.name)); - } + ObjectSafetyViolation::SupertraitSelf => { + tcx.sess.span_note( + span, + "the trait cannot use `Self` as a type parameter \ + in the supertrait listing"); + } - ObjectSafetyViolation::Method(method, - MethodViolationCode::ReferencesSelf) => { - infcx.tcx.sess.span_note( - obligation.cause.span, - &format!("method `{}` references the `Self` type \ - in its arguments or return type", - method.name)); - } + ObjectSafetyViolation::Method(method, + MethodViolationCode::StaticMethod) => { + tcx.sess.span_note( + span, + &format!("method `{}` has no receiver", + method.name)); + } - ObjectSafetyViolation::Method(method, - MethodViolationCode::Generic) => { - infcx.tcx.sess.span_note( - obligation.cause.span, - &format!("method `{}` has generic type parameters", - method.name)); - } - } + ObjectSafetyViolation::Method(method, + MethodViolationCode::ReferencesSelf) => { + tcx.sess.span_note( + span, + &format!("method `{}` references the `Self` type \ + in its arguments or return type", + method.name)); + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::Generic) => { + tcx.sess.span_note( + span, + &format!("method `{}` has generic type parameters", + method.name)); } } } @@ -342,14 +387,11 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, infcx.tcx.lang_items.sized_trait() .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { - span_err!(infcx.tcx.sess, obligation.cause.span, E0282, - "unable to infer enough type information about `{}`; \ - type annotations or generic parameter binding required", - self_ty); + need_type_info(infcx, obligation.cause.span, self_ty); } else { span_err!(infcx.tcx.sess, obligation.cause.span, E0283, "type annotations required: cannot resolve `{}`", - predicate);; + predicate); note_obligation_cause(infcx, obligation); } } @@ -366,6 +408,14 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } } + ty::Predicate::WellFormed(ty) => { + // Same hacky approach as above to avoid deluging user + // with error messages. + if !ty.references_error() && !infcx.tcx.sess.has_errors() { + need_type_info(infcx, obligation.cause.span, ty); + } + } + _ => { if !infcx.tcx.sess.has_errors() { span_err!(infcx.tcx.sess, obligation.cause.span, E0284, @@ -377,6 +427,16 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } } +fn need_type_info<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + span: Span, + ty: Ty<'tcx>) +{ + span_err!(infcx.tcx.sess, span, E0282, + "unable to infer enough type information about `{}`; \ + type annotations or generic parameter binding required", + ty); +} + fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, obligation: &Obligation<'tcx, T>) where T: fmt::Display @@ -396,6 +456,27 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, let tcx = infcx.tcx; match *cause_code { ObligationCauseCode::MiscObligation => { } + ObligationCauseCode::RFC1214(ref subcode) => { + tcx.sess.note_rfc_1214(cause_span); + note_obligation_cause_code(infcx, predicate, cause_span, subcode); + } + ObligationCauseCode::SliceOrArrayElem => { + tcx.sess.span_note( + cause_span, + &format!("slice and array elements must have `Sized` type")); + } + ObligationCauseCode::ProjectionWf(data) => { + tcx.sess.span_note( + cause_span, + &format!("required so that the projection `{}` is well-formed", + data)); + } + ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { + tcx.sess.span_note( + cause_span, + &format!("required so that reference `{}` does not outlive its referent", + ref_ty)); + } ObligationCauseCode::ItemObligation(item_def_id) => { let item_name = tcx.item_path_str(item_def_id); tcx.sess.span_note( diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 376430e87c6f..14ab6c505d05 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -27,6 +27,7 @@ use syntax::codemap::{Span, DUMMY_SP}; pub use self::error_reporting::report_fulfillment_errors; pub use self::error_reporting::report_overflow_error; pub use self::error_reporting::report_selection_error; +pub use self::error_reporting::report_object_safety_error; pub use self::error_reporting::suggest_new_overflow_limit; pub use self::coherence::orphan_check; pub use self::coherence::overlapping_impls; @@ -80,7 +81,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; /// Why did we incur this obligation? Used for error reporting. -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct ObligationCause<'tcx> { pub span: Span, @@ -95,15 +96,27 @@ pub struct ObligationCause<'tcx> { pub code: ObligationCauseCode<'tcx> } -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from span. MiscObligation, + /// Obligation that triggers warning until RFC 1214 is fully in place. + RFC1214(Rc>), + + /// This is the trait reference from the given projection + SliceOrArrayElem, + + /// This is the trait reference from the given projection + ProjectionWf(ty::ProjectionTy<'tcx>), + /// In an impl of trait X for type Y, type Y must /// also implement all supertraits of X. ItemObligation(ast::DefId), + /// A type like `&'a T` is WF only if `T: 'a`. + ReferenceOutlivesReferent(Ty<'tcx>), + /// Obligation incurred due to an object cast. ObjectCastObligation(/* Object type */ Ty<'tcx>), @@ -124,7 +137,6 @@ pub enum ObligationCauseCode<'tcx> { // static items must have `Sync` type SharedStatic, - BuiltinDerivedObligation(DerivedObligationCause<'tcx>), ImplDerivedObligation(DerivedObligationCause<'tcx>), @@ -132,7 +144,7 @@ pub enum ObligationCauseCode<'tcx> { CompareImplMethodObligation, } -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct DerivedObligationCause<'tcx> { /// The trait reference of the parent obligation that led to the /// current obligation. Note that only trait obligations lead to @@ -516,6 +528,15 @@ impl<'tcx> ObligationCause<'tcx> { } } +impl<'tcx> ObligationCauseCode<'tcx> { + pub fn is_rfc1214(&self) -> bool { + match *self { + ObligationCauseCode::RFC1214(..) => true, + _ => false, + } + } +} + impl<'tcx, N> Vtable<'tcx, N> { pub fn nested_obligations(self) -> Vec { match self { diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 6c568b656c04..713b7394b59a 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -2920,13 +2920,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // chain. Ideally, we should have a way to configure this either // by using -Z verbose or just a CLI argument. if obligation.recursion_depth >= 0 { - let derived_cause = DerivedObligationCause { - parent_trait_ref: obligation.predicate.to_poly_trait_ref(), - parent_code: Rc::new(obligation.cause.code.clone()), + let derived_code = match obligation.cause.code { + ObligationCauseCode::RFC1214(ref base_code) => { + let derived_cause = DerivedObligationCause { + parent_trait_ref: obligation.predicate.to_poly_trait_ref(), + parent_code: base_code.clone(), + }; + ObligationCauseCode::RFC1214(Rc::new(variant(derived_cause))) + } + _ => { + let derived_cause = DerivedObligationCause { + parent_trait_ref: obligation.predicate.to_poly_trait_ref(), + parent_code: Rc::new(obligation.cause.code.clone()) + }; + variant(derived_cause) + } }; - ObligationCause::new(obligation.cause.span, - obligation.cause.body_id, - variant(derived_cause)) + ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) } else { obligation.cause.clone() } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 99a58f07ae62..ffb3a8ccb36b 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -90,6 +90,13 @@ impl Session { } self.diagnostic().handler().fatal(msg) } + pub fn span_err_or_warn(&self, is_warning: bool, sp: Span, msg: &str) { + if is_warning { + self.span_warn(sp, msg); + } else { + self.span_err(sp, msg); + } + } pub fn span_err(&self, sp: Span, msg: &str) { if self.opts.treat_err_as_bug { self.span_bug(sp, msg); @@ -99,6 +106,13 @@ impl Session { None => self.diagnostic().span_err(sp, msg) } } + pub fn note_rfc_1214(&self, span: Span) { + self.span_note( + span, + &format!("this warning results from recent bug fixes and clarifications; \ + it will become a HARD ERROR in the next release. \ + See RFC 1214 for details.")); + } pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { if self.opts.treat_err_as_bug { self.span_bug(sp, msg); diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 669b930ecc92..3c8347f8a8e0 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -30,6 +30,18 @@ macro_rules! span_err { }) } +#[macro_export] +macro_rules! span_err_or_warn { + ($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ + __diagnostic_used!($code); + if $is_warning { + $session.span_warn_with_code($span, &format!($($message)*), stringify!($code)) + } else { + $session.span_err_with_code($span, &format!($($message)*), stringify!($code)) + } + }) +} + #[macro_export] macro_rules! span_warn { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({