use crate::errors::{ note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, RefLongerThanData, RegionOriginNote, WhereClauseSuggestions, }; use crate::fluent_generated as fluent; use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; use crate::infer::{self, SubregionOrigin}; use rustc_errors::{ AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, }; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, IsSuggestable, Region}; use rustc_span::symbol::kw; use super::ObligationCauseAsDiagArg; impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) { match *origin { infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { span: trace.cause.span, requirement: ObligationCauseAsDiagArg(trace.cause.clone()), expected_found: self.values_str(trace.values).map(|(e, f, _, _)| (e, f)), } .add_to_diagnostic(err), infer::Reborrow(span) => { RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err) } infer::RelateObjectBound(span) => { RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound } .add_to_diagnostic(err); } infer::ReferenceOutlivesReferent(ty, span) => { RegionOriginNote::WithName { span, msg: fluent::infer_reference_outlives_referent, name: &self.ty_to_string(ty), continues: false, } .add_to_diagnostic(err); } infer::RelateParamBound(span, ty, opt_span) => { RegionOriginNote::WithName { span, msg: fluent::infer_relate_param_bound, name: &self.ty_to_string(ty), continues: opt_span.is_some(), } .add_to_diagnostic(err); if let Some(span) = opt_span { RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 } .add_to_diagnostic(err); } } infer::RelateRegionParamBound(span) => { RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound } .add_to_diagnostic(err); } infer::CompareImplItemObligation { span, .. } => { RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation } .add_to_diagnostic(err); } infer::CheckAssociatedTypeBounds { ref parent, .. } => { self.note_region_origin(err, &parent); } infer::AscribeUserTypeProvePredicate(span) => { RegionOriginNote::Plain { span, msg: fluent::infer_ascribe_user_type_prove_predicate, } .add_to_diagnostic(err); } } } pub(super) fn report_concrete_failure( &self, origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let mut err = 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 reference_valid = note_and_explain::RegionExplanation::new( self.tcx, sub, None, note_and_explain::PrefixKind::RefValidFor, note_and_explain::SuffixKind::Continues, ); let content_valid = note_and_explain::RegionExplanation::new( self.tcx, sup, None, note_and_explain::PrefixKind::ContentValidFor, note_and_explain::SuffixKind::Empty, ); OutlivesContent { span, notes: reference_valid.into_iter().chain(content_valid).collect(), } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } infer::RelateObjectBound(span) => { let object_valid = note_and_explain::RegionExplanation::new( self.tcx, sub, None, note_and_explain::PrefixKind::TypeObjValidFor, note_and_explain::SuffixKind::Empty, ); let pointer_valid = note_and_explain::RegionExplanation::new( self.tcx, sup, None, note_and_explain::PrefixKind::SourcePointerValidFor, note_and_explain::SuffixKind::Empty, ); OutlivesBound { span, notes: object_valid.into_iter().chain(pointer_valid).collect(), } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } infer::RelateParamBound(span, ty, opt_span) => { let prefix = match *sub { ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy, _ => note_and_explain::PrefixKind::TypeOutlive, }; let suffix = if opt_span.is_some() { note_and_explain::SuffixKind::ReqByBinding } else { note_and_explain::SuffixKind::Empty }; let note = note_and_explain::RegionExplanation::new( self.tcx, sub, opt_span, prefix, suffix, ); FullfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } infer::RelateRegionParamBound(span) => { let param_instantiated = note_and_explain::RegionExplanation::new( self.tcx, sup, None, note_and_explain::PrefixKind::LfParamInstantiatedWith, note_and_explain::SuffixKind::Empty, ); let param_must_outlive = note_and_explain::RegionExplanation::new( self.tcx, sub, None, note_and_explain::PrefixKind::LfParamMustOutlive, note_and_explain::SuffixKind::Empty, ); LfBoundNotSatisfied { span, notes: param_instantiated.into_iter().chain(param_must_outlive).collect(), } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } infer::ReferenceOutlivesReferent(ty, span) => { let pointer_valid = note_and_explain::RegionExplanation::new( self.tcx, sub, None, note_and_explain::PrefixKind::PointerValidFor, note_and_explain::SuffixKind::Empty, ); let data_valid = note_and_explain::RegionExplanation::new( self.tcx, sup, None, note_and_explain::PrefixKind::DataValidFor, note_and_explain::SuffixKind::Empty, ); RefLongerThanData { span, ty: self.resolve_vars_if_possible(ty), notes: pointer_valid.into_iter().chain(data_valid).collect(), } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { let mut err = self.report_extra_impl_obligation( span, impl_item_def_id, trait_item_def_id, &format!("`{}: {}`", sup, sub), ); // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) && generics.where_clause_span.contains(span) { self.suggest_copy_trait_method_bounds( trait_item_def_id, impl_item_def_id, &mut err, ); } err } 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), ); self.suggest_copy_trait_method_bounds( trait_item_def_id, impl_item_def_id, &mut err, ); err } infer::AscribeUserTypeProvePredicate(span) => { let instantiated = note_and_explain::RegionExplanation::new( self.tcx, sup, None, note_and_explain::PrefixKind::LfInstantiatedWith, note_and_explain::SuffixKind::Empty, ); let must_outlive = note_and_explain::RegionExplanation::new( self.tcx, sub, None, note_and_explain::PrefixKind::LfMustOutlive, note_and_explain::SuffixKind::Empty, ); LfBoundNotSatisfied { span, notes: instantiated.into_iter().chain(must_outlive).collect(), } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } }; if sub.is_error() || sup.is_error() { err.delay_as_bug(); } err } pub fn suggest_copy_trait_method_bounds( &self, trait_item_def_id: DefId, impl_item_def_id: LocalDefId, err: &mut Diagnostic, ) { // FIXME(compiler-errors): Right now this is only being used for region // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches, // but right now it's not really very smart when it comes to implicit `Sized` // predicates and bounds on the trait itself. let Some(impl_def_id) = self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) else { return; }; let Some(trait_ref) = self .tcx .impl_trait_ref(impl_def_id) else { return; }; let trait_substs = trait_ref .subst_identity() // Replace the explicit self type with `Self` for better suggestion rendering .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper)) .substs; let trait_item_substs = ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id()) .rebase_onto(self.tcx, impl_def_id, trait_substs); let Ok(trait_predicates) = self .tcx .explicit_predicates_of(trait_item_def_id) .instantiate_own(self.tcx, trait_item_substs) .map(|(pred, _)| { if pred.is_suggestable(self.tcx, false) { Ok(pred.to_string()) } else { Err(()) } }) .collect::, ()>>() else { return; }; let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; }; let suggestion = if trait_predicates.is_empty() { WhereClauseSuggestions::Remove { span: generics.where_clause_span } } else { let space = if generics.where_clause_span.is_empty() { " " } else { "" }; WhereClauseSuggestions::CopyPredicates { span: generics.where_clause_span, space, trait_predicates: trait_predicates.join(", "), } }; err.subdiagnostic(suggestion); } 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(..) | ObligationCauseCode::ExprBindingObligation(..) ) => { // Hack to get around the borrow checker because trace.cause has an `Rc`. if let ObligationCauseCode::BindingObligation(_, span) | ObligationCauseCode::ExprBindingObligation(_, 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), } } }