use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt}; use crate::infer::{self, InferCtxt, SubregionOrigin}; use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Region}; impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) { let mut label_or_note = |span, msg: &str| { let sub_count = err.children.iter().filter(|d| d.span.is_dummy()).count(); let expanded_sub_count = err.children.iter().filter(|d| !d.span.is_dummy()).count(); let span_is_primary = err.span.primary_spans().iter().all(|&sp| sp == span); if span_is_primary && sub_count == 0 && expanded_sub_count == 0 { err.span_label(span, msg); } else if span_is_primary && expanded_sub_count == 0 { err.note(msg); } else { err.span_note(span, msg); } }; match *origin { infer::Subtype(ref trace) => { if let Some((expected, found)) = self.values_str(trace.values) { label_or_note( trace.cause.span, &format!("...so that the {}", trace.cause.as_requirement_str()), ); err.note_expected_found(&"", expected, &"", found); } else { // FIXME: this really should be handled at some earlier stage. Our // handling of region checking when type errors are present is // *terrible*. label_or_note( trace.cause.span, &format!("...so that {}", trace.cause.as_requirement_str()), ); } } infer::Reborrow(span) => { label_or_note(span, "...so that reference does not outlive borrowed content"); } infer::ReborrowUpvar(span, ref upvar_id) => { let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); label_or_note(span, &format!("...so that closure can access `{}`", var_name)); } infer::RelateObjectBound(span) => { label_or_note(span, "...so that it can be closed over into an object"); } infer::DataBorrowed(ty, span) => { label_or_note( span, &format!( "...so that the type `{}` is not borrowed for too long", self.ty_to_string(ty) ), ); } infer::ReferenceOutlivesReferent(ty, span) => { label_or_note( span, &format!( "...so that the reference type `{}` does not outlive the data it points at", self.ty_to_string(ty) ), ); } infer::RelateParamBound(span, t, opt_span) => { label_or_note( span, &format!( "...so that the type `{}` will meet its required lifetime bounds{}", self.ty_to_string(t), if opt_span.is_some() { "..." } else { "" }, ), ); if let Some(span) = opt_span { err.span_note(span, "...that is required by this bound"); } } infer::RelateRegionParamBound(span) => { label_or_note( span, "...so that the declared lifetime parameter bounds are satisfied", ); } infer::CompareImplItemObligation { span, .. } => { label_or_note( span, "...so that the definition in impl matches the definition from the trait", ); } infer::CheckAssociatedTypeBounds { ref parent, .. } => { self.note_region_origin(err, &parent); } } } pub(super) fn report_concrete_failure( &self, origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { match origin { infer::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); let mut err = self.report_and_explain_type_error(trace, &terr); match (*sub, *sup) { (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} (ty::RePlaceholder(_), _) => { note_and_explain_region( self.tcx, &mut err, "", sup, " doesn't meet the lifetime requirements", None, ); } (_, ty::RePlaceholder(_)) => { note_and_explain_region( self.tcx, &mut err, "the required lifetime does not necessarily outlive ", sub, "", None, ); } _ => { note_and_explain_region(self.tcx, &mut err, "", sup, "...", None); note_and_explain_region( self.tcx, &mut err, "...does not necessarily outlive ", sub, "", None, ); } } err } infer::Reborrow(span) => { let mut err = struct_span_err!( self.tcx.sess, span, E0312, "lifetime of reference outlives lifetime of borrowed content..." ); note_and_explain_region( self.tcx, &mut err, "...the reference is valid for ", sub, "...", None, ); note_and_explain_region( self.tcx, &mut err, "...but the borrowed content is only valid for ", sup, "", None, ); err } infer::ReborrowUpvar(span, ref upvar_id) => { let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); let mut err = struct_span_err!( self.tcx.sess, span, E0313, "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...", var_name ); note_and_explain_region( self.tcx, &mut err, "...the borrowed pointer is valid for ", sub, "...", None, ); note_and_explain_region( self.tcx, &mut err, &format!("...but `{}` is only valid for ", var_name), sup, "", None, ); err } infer::RelateObjectBound(span) => { let mut err = struct_span_err!( self.tcx.sess, span, E0476, "lifetime of the source pointer does not outlive lifetime bound of the \ object type" ); note_and_explain_region( self.tcx, &mut err, "object type is valid for ", sub, "", None, ); note_and_explain_region( self.tcx, &mut err, "source pointer is only valid for ", sup, "", None, ); err } infer::RelateParamBound(span, ty, opt_span) => { let mut err = struct_span_err!( self.tcx.sess, span, E0477, "the type `{}` does not fulfill the required lifetime", self.ty_to_string(ty) ); match *sub { ty::ReStatic => note_and_explain_region( self.tcx, &mut err, "type must satisfy ", sub, if opt_span.is_some() { " as required by this binding" } else { "" }, opt_span, ), _ => note_and_explain_region( self.tcx, &mut err, "type must outlive ", sub, if opt_span.is_some() { " as required by this binding" } else { "" }, opt_span, ), } err } infer::RelateRegionParamBound(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied"); note_and_explain_region( self.tcx, &mut err, "lifetime parameter instantiated with ", sup, "", None, ); note_and_explain_region( self.tcx, &mut err, "but lifetime parameter must outlive ", sub, "", None, ); err } infer::DataBorrowed(ty, span) => { let mut err = struct_span_err!( self.tcx.sess, span, E0490, "a value of type `{}` is borrowed for too long", self.ty_to_string(ty) ); note_and_explain_region( self.tcx, &mut err, "the type is valid for ", sub, "", None, ); note_and_explain_region( self.tcx, &mut err, "but the borrow lasts for ", sup, "", None, ); err } infer::ReferenceOutlivesReferent(ty, span) => { let mut err = struct_span_err!( self.tcx.sess, span, E0491, "in type `{}`, reference has a longer lifetime than the data it references", self.ty_to_string(ty) ); note_and_explain_region( self.tcx, &mut err, "the pointer is valid for ", sub, "", None, ); note_and_explain_region( self.tcx, &mut err, "but the referenced data is only valid for ", sup, "", None, ); err } infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self .report_extra_impl_obligation( span, impl_item_def_id, trait_item_def_id, &format!("`{}: {}`", sup, sub), ), infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { let mut err = self.report_concrete_failure(*parent, sub, sup); let trait_item_span = self.tcx.def_span(trait_item_def_id); let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); err.span_label( trait_item_span, format!("definition of `{}` from trait", item_name), ); let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id); let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id); let impl_predicates: rustc_data_structures::fx::FxHashSet<_> = impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect(); let clauses: Vec<_> = trait_predicates .predicates .into_iter() .filter(|&(pred, _)| !impl_predicates.contains(pred)) .map(|(pred, _)| format!("{}", pred)) .collect(); if !clauses.is_empty() { let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap(); let where_clause_span = generics.tail_span_for_predicate_suggestion(); let suggestion = format!( "{} {}", generics.add_where_or_trailing_comma(), clauses.join(", "), ); err.span_suggestion( where_clause_span, &format!( "try copying {} from the trait", if clauses.len() > 1 { "these clauses" } else { "this clause" } ), suggestion, rustc_errors::Applicability::MaybeIncorrect, ); } err } } } pub(super) fn report_placeholder_failure( &self, placeholder_origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { // I can't think how to do better than this right now. -nikomatsakis debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); match placeholder_origin { infer::Subtype(box ref trace) if matches!( &trace.cause.code().peel_derives(), ObligationCauseCode::BindingObligation(..) ) => { // Hack to get around the borrow checker because trace.cause has an `Rc`. if let ObligationCauseCode::BindingObligation(_, span) = &trace.cause.code().peel_derives() { let span = *span; let mut err = self.report_concrete_failure(placeholder_origin, sub, sup); err.span_note(span, "the lifetime requirement is introduced here"); err } else { unreachable!() } } infer::Subtype(box trace) => { let terr = TypeError::RegionsPlaceholderMismatch; return self.report_and_explain_type_error(trace, &terr); } _ => return self.report_concrete_failure(placeholder_origin, sub, sup), } } }