diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 3f38850c8ff..635de28194d 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -73,6 +73,7 @@ use middle::typeck::infer::region_inference::SubSupConflict; use middle::typeck::infer::region_inference::SupSupConflict; use syntax::opt_vec::OptVec; use util::ppaux::UserString; +use util::ppaux::bound_region_to_str; use util::ppaux::note_and_explain_region; pub trait ErrorReporting { @@ -110,6 +111,13 @@ pub trait ErrorReporting { region2: Region); } +trait ErrorReportingHelpers { + fn report_inference_failure(@mut self, + var_origin: RegionVariableOrigin); + + fn note_region_origin(@mut self, + origin: SubregionOrigin); +} impl ErrorReporting for InferCtxt { fn report_region_errors(@mut self, @@ -398,10 +406,7 @@ impl ErrorReporting for InferCtxt { sub_region: Region, sup_origin: SubregionOrigin, sup_region: Region) { - self.tcx.sess.span_err( - var_origin.span(), - format!("cannot infer an appropriate lifetime \ - due to conflicting requirements")); + self.report_inference_failure(var_origin); note_and_explain_region( self.tcx, @@ -409,9 +414,7 @@ impl ErrorReporting for InferCtxt { sup_region, "..."); - self.tcx.sess.span_note( - sup_origin.span(), - format!("...due to the following expression")); + self.note_region_origin(sup_origin); note_and_explain_region( self.tcx, @@ -419,9 +422,7 @@ impl ErrorReporting for InferCtxt { sub_region, "..."); - self.tcx.sess.span_note( - sub_origin.span(), - format!("...due to the following expression")); + self.note_region_origin(sub_origin); } fn report_sup_sup_conflict(@mut self, @@ -430,10 +431,7 @@ impl ErrorReporting for InferCtxt { region1: Region, origin2: SubregionOrigin, region2: Region) { - self.tcx.sess.span_err( - var_origin.span(), - format!("cannot infer an appropriate lifetime \ - due to conflicting requirements")); + self.report_inference_failure(var_origin); note_and_explain_region( self.tcx, @@ -441,9 +439,7 @@ impl ErrorReporting for InferCtxt { region1, "..."); - self.tcx.sess.span_note( - origin1.span(), - format!("...due to the following expression")); + self.note_region_origin(origin1); note_and_explain_region( self.tcx, @@ -451,9 +447,167 @@ impl ErrorReporting for InferCtxt { region2, "..."); - self.tcx.sess.span_note( - origin2.span(), - format!("...due to the following expression")); + self.note_region_origin(origin2); + } +} + +impl ErrorReportingHelpers for InferCtxt { + fn report_inference_failure(@mut self, + var_origin: RegionVariableOrigin) { + let var_description = match var_origin { + infer::MiscVariable(_) => ~"", + infer::PatternRegion(_) => ~" for pattern", + infer::AddrOfRegion(_) => ~" for borrow expression", + infer::AddrOfSlice(_) => ~" for slice expression", + infer::Autoref(_) => ~" for autoref", + infer::Coercion(_) => ~" for automatic coercion", + infer::BoundRegionInFnCall(_, br) => { + format!(" for {}in function call", + bound_region_to_str(self.tcx, "region ", true, br)) + } + infer::BoundRegionInFnType(_, br) => { + format!(" for {}in function type", + bound_region_to_str(self.tcx, "region ", true, br)) + } + infer::BoundRegionInTypeOrImpl(_) => { + format!(" for region in type/impl") + } + infer::BoundRegionInCoherence(*) => { + format!(" for coherence check") + } + }; + + self.tcx.sess.span_err( + var_origin.span(), + format!("cannot infer an appropriate lifetime{} \ + due to conflicting requirements", + var_description)); + } + + fn note_region_origin(@mut self, + origin: SubregionOrigin) { + match origin { + infer::Subtype(ref trace) => { + let desc = match trace.origin { + infer::Misc(_) => { + format!("types are compatible") + } + infer::MethodCompatCheck(_) => { + format!("method type is compatible with trait") + } + infer::ExprAssignable(_) => { + format!("expression is assignable") + } + infer::RelateTraitRefs(_) => { + format!("traits are compatible") + } + infer::RelateSelfType(_) => { + format!("type matches impl") + } + infer::MatchExpression(_) => { + format!("match arms have compatible types") + } + infer::IfExpression(_) => { + format!("if and else have compatible types") + } + }; + + match self.values_str(&trace.values) { + Some(values_str) => { + self.tcx.sess.span_note( + trace.origin.span(), + format!("...so that {} ({})", + desc, values_str)); + } + None => { + // Really should avoid printing this error at + // all, since it is derived, but that would + // require more refactoring than I feel like + // doing right now. - nmatsakis + self.tcx.sess.span_note( + trace.origin.span(), + format!("...so that {}", desc)); + } + } + } + infer::Reborrow(span) => { + self.tcx.sess.span_note( + span, + "...so that borrowed pointer does not outlive \ + borrowed content"); + } + infer::InfStackClosure(span) => { + self.tcx.sess.span_note( + span, + "...so that closure does not outlive its stack frame"); + } + infer::InvokeClosure(span) => { + self.tcx.sess.span_note( + span, + "...so that closure is not invoked outside its lifetime"); + } + infer::DerefPointer(span) => { + self.tcx.sess.span_note( + span, + "...so that pointer is not dereferenced \ + outside its lifetime"); + } + infer::FreeVariable(span) => { + self.tcx.sess.span_note( + span, + "...so that captured variable does not outlive the \ + enclosing closure"); + } + infer::IndexSlice(span) => { + self.tcx.sess.span_note( + span, + "...so that slice is not indexed outside the lifetime"); + } + infer::RelateObjectBound(span) => { + self.tcx.sess.span_note( + span, + "...so that source pointer does not outlive \ + lifetime bound of the object type"); + } + infer::CallRcvr(span) => { + self.tcx.sess.span_note( + span, + "...so that method receiver is valid for the method call"); + } + infer::CallArg(span) => { + self.tcx.sess.span_note( + span, + "...so that argument is valid for the call"); + } + infer::CallReturn(span) => { + self.tcx.sess.span_note( + span, + "...so that return value is valid for the call"); + } + infer::AddrOf(span) => { + self.tcx.sess.span_note( + span, + "...so that borrowed pointer is valid \ + at the time of borrow"); + } + infer::AutoBorrow(span) => { + self.tcx.sess.span_note( + span, + "...so that automatically borrowed pointer is valid \ + at the time of borrow"); + } + infer::BindingTypeIsNotValidAtDecl(span) => { + self.tcx.sess.span_note( + span, + "...so that variable is valid at time of its declaration"); + } + infer::ReferenceOutlivesReferent(_, span) => { + self.tcx.sess.span_note( + span, + "...so that the pointer does not outlive the \ + data it points at"); + } + } } }