1 use crate::errors::{ 2 note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, 3 RefLongerThanData, RegionOriginNote, WhereClauseSuggestions, 4 }; 5 use crate::fluent_generated as fluent; 6 use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; 7 use crate::infer::{self, SubregionOrigin}; 8 use rustc_errors::{ 9 AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, 10 }; 11 use rustc_hir::def_id::{DefId, LocalDefId}; 12 use rustc_middle::traits::ObligationCauseCode; 13 use rustc_middle::ty::error::TypeError; 14 use rustc_middle::ty::{self, IsSuggestable, Region, Ty}; 15 use rustc_span::symbol::kw; 16 17 use super::ObligationCauseAsDiagArg; 18 19 impl<'tcx> TypeErrCtxt<'_, 'tcx> { note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>)20 pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) { 21 match *origin { 22 infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { 23 span: trace.cause.span, 24 requirement: ObligationCauseAsDiagArg(trace.cause.clone()), 25 expected_found: self.values_str(trace.values).map(|(e, f, _, _)| (e, f)), 26 } 27 .add_to_diagnostic(err), 28 infer::Reborrow(span) => { 29 RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err) 30 } 31 infer::RelateObjectBound(span) => { 32 RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound } 33 .add_to_diagnostic(err); 34 } 35 infer::ReferenceOutlivesReferent(ty, span) => { 36 RegionOriginNote::WithName { 37 span, 38 msg: fluent::infer_reference_outlives_referent, 39 name: &self.ty_to_string(ty), 40 continues: false, 41 } 42 .add_to_diagnostic(err); 43 } 44 infer::RelateParamBound(span, ty, opt_span) => { 45 RegionOriginNote::WithName { 46 span, 47 msg: fluent::infer_relate_param_bound, 48 name: &self.ty_to_string(ty), 49 continues: opt_span.is_some(), 50 } 51 .add_to_diagnostic(err); 52 if let Some(span) = opt_span { 53 RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 } 54 .add_to_diagnostic(err); 55 } 56 } 57 infer::RelateRegionParamBound(span) => { 58 RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound } 59 .add_to_diagnostic(err); 60 } 61 infer::CompareImplItemObligation { span, .. } => { 62 RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation } 63 .add_to_diagnostic(err); 64 } 65 infer::CheckAssociatedTypeBounds { ref parent, .. } => { 66 self.note_region_origin(err, &parent); 67 } 68 infer::AscribeUserTypeProvePredicate(span) => { 69 RegionOriginNote::Plain { 70 span, 71 msg: fluent::infer_ascribe_user_type_prove_predicate, 72 } 73 .add_to_diagnostic(err); 74 } 75 } 76 } 77 report_concrete_failure( &self, origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>78 pub(super) fn report_concrete_failure( 79 &self, 80 origin: SubregionOrigin<'tcx>, 81 sub: Region<'tcx>, 82 sup: Region<'tcx>, 83 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 84 let mut err = match origin { 85 infer::Subtype(box trace) => { 86 let terr = TypeError::RegionsDoesNotOutlive(sup, sub); 87 let mut err = self.report_and_explain_type_error(trace, terr); 88 match (*sub, *sup) { 89 (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} 90 (ty::RePlaceholder(_), _) => { 91 note_and_explain_region( 92 self.tcx, 93 &mut err, 94 "", 95 sup, 96 " doesn't meet the lifetime requirements", 97 None, 98 ); 99 } 100 (_, ty::RePlaceholder(_)) => { 101 note_and_explain_region( 102 self.tcx, 103 &mut err, 104 "the required lifetime does not necessarily outlive ", 105 sub, 106 "", 107 None, 108 ); 109 } 110 _ => { 111 note_and_explain_region(self.tcx, &mut err, "", sup, "...", None); 112 note_and_explain_region( 113 self.tcx, 114 &mut err, 115 "...does not necessarily outlive ", 116 sub, 117 "", 118 None, 119 ); 120 } 121 } 122 err 123 } 124 infer::Reborrow(span) => { 125 let reference_valid = note_and_explain::RegionExplanation::new( 126 self.tcx, 127 sub, 128 None, 129 note_and_explain::PrefixKind::RefValidFor, 130 note_and_explain::SuffixKind::Continues, 131 ); 132 let content_valid = note_and_explain::RegionExplanation::new( 133 self.tcx, 134 sup, 135 None, 136 note_and_explain::PrefixKind::ContentValidFor, 137 note_and_explain::SuffixKind::Empty, 138 ); 139 OutlivesContent { 140 span, 141 notes: reference_valid.into_iter().chain(content_valid).collect(), 142 } 143 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) 144 } 145 infer::RelateObjectBound(span) => { 146 let object_valid = note_and_explain::RegionExplanation::new( 147 self.tcx, 148 sub, 149 None, 150 note_and_explain::PrefixKind::TypeObjValidFor, 151 note_and_explain::SuffixKind::Empty, 152 ); 153 let pointer_valid = note_and_explain::RegionExplanation::new( 154 self.tcx, 155 sup, 156 None, 157 note_and_explain::PrefixKind::SourcePointerValidFor, 158 note_and_explain::SuffixKind::Empty, 159 ); 160 OutlivesBound { 161 span, 162 notes: object_valid.into_iter().chain(pointer_valid).collect(), 163 } 164 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) 165 } 166 infer::RelateParamBound(span, ty, opt_span) => { 167 let prefix = match *sub { 168 ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy, 169 _ => note_and_explain::PrefixKind::TypeOutlive, 170 }; 171 let suffix = if opt_span.is_some() { 172 note_and_explain::SuffixKind::ReqByBinding 173 } else { 174 note_and_explain::SuffixKind::Empty 175 }; 176 let note = note_and_explain::RegionExplanation::new( 177 self.tcx, sub, opt_span, prefix, suffix, 178 ); 179 FulfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note } 180 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) 181 } 182 infer::RelateRegionParamBound(span) => { 183 let param_instantiated = note_and_explain::RegionExplanation::new( 184 self.tcx, 185 sup, 186 None, 187 note_and_explain::PrefixKind::LfParamInstantiatedWith, 188 note_and_explain::SuffixKind::Empty, 189 ); 190 let param_must_outlive = note_and_explain::RegionExplanation::new( 191 self.tcx, 192 sub, 193 None, 194 note_and_explain::PrefixKind::LfParamMustOutlive, 195 note_and_explain::SuffixKind::Empty, 196 ); 197 LfBoundNotSatisfied { 198 span, 199 notes: param_instantiated.into_iter().chain(param_must_outlive).collect(), 200 } 201 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) 202 } 203 infer::ReferenceOutlivesReferent(ty, span) => { 204 let pointer_valid = note_and_explain::RegionExplanation::new( 205 self.tcx, 206 sub, 207 None, 208 note_and_explain::PrefixKind::PointerValidFor, 209 note_and_explain::SuffixKind::Empty, 210 ); 211 let data_valid = note_and_explain::RegionExplanation::new( 212 self.tcx, 213 sup, 214 None, 215 note_and_explain::PrefixKind::DataValidFor, 216 note_and_explain::SuffixKind::Empty, 217 ); 218 RefLongerThanData { 219 span, 220 ty: self.resolve_vars_if_possible(ty), 221 notes: pointer_valid.into_iter().chain(data_valid).collect(), 222 } 223 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) 224 } 225 infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { 226 let mut err = self.report_extra_impl_obligation( 227 span, 228 impl_item_def_id, 229 trait_item_def_id, 230 &format!("`{}: {}`", sup, sub), 231 ); 232 // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause 233 if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) 234 && generics.where_clause_span.contains(span) 235 { 236 self.suggest_copy_trait_method_bounds( 237 trait_item_def_id, 238 impl_item_def_id, 239 &mut err, 240 ); 241 } 242 err 243 } 244 infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { 245 let mut err = self.report_concrete_failure(*parent, sub, sup); 246 let trait_item_span = self.tcx.def_span(trait_item_def_id); 247 let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); 248 err.span_label( 249 trait_item_span, 250 format!("definition of `{}` from trait", item_name), 251 ); 252 self.suggest_copy_trait_method_bounds( 253 trait_item_def_id, 254 impl_item_def_id, 255 &mut err, 256 ); 257 err 258 } 259 infer::AscribeUserTypeProvePredicate(span) => { 260 let instantiated = note_and_explain::RegionExplanation::new( 261 self.tcx, 262 sup, 263 None, 264 note_and_explain::PrefixKind::LfInstantiatedWith, 265 note_and_explain::SuffixKind::Empty, 266 ); 267 let must_outlive = note_and_explain::RegionExplanation::new( 268 self.tcx, 269 sub, 270 None, 271 note_and_explain::PrefixKind::LfMustOutlive, 272 note_and_explain::SuffixKind::Empty, 273 ); 274 LfBoundNotSatisfied { 275 span, 276 notes: instantiated.into_iter().chain(must_outlive).collect(), 277 } 278 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) 279 } 280 }; 281 if sub.is_error() || sup.is_error() { 282 err.delay_as_bug(); 283 } 284 err 285 } 286 suggest_copy_trait_method_bounds( &self, trait_item_def_id: DefId, impl_item_def_id: LocalDefId, err: &mut Diagnostic, )287 pub fn suggest_copy_trait_method_bounds( 288 &self, 289 trait_item_def_id: DefId, 290 impl_item_def_id: LocalDefId, 291 err: &mut Diagnostic, 292 ) { 293 // FIXME(compiler-errors): Right now this is only being used for region 294 // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches, 295 // but right now it's not really very smart when it comes to implicit `Sized` 296 // predicates and bounds on the trait itself. 297 298 let Some(impl_def_id) = 299 self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) else { return; }; 300 let Some(trait_ref) = self 301 .tcx 302 .impl_trait_ref(impl_def_id) 303 else { return; }; 304 let trait_substs = trait_ref 305 .subst_identity() 306 // Replace the explicit self type with `Self` for better suggestion rendering 307 .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper)) 308 .substs; 309 let trait_item_substs = ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id) 310 .rebase_onto(self.tcx, impl_def_id, trait_substs); 311 312 let Ok(trait_predicates) = self 313 .tcx 314 .explicit_predicates_of(trait_item_def_id) 315 .instantiate_own(self.tcx, trait_item_substs) 316 .map(|(pred, _)| { 317 if pred.is_suggestable(self.tcx, false) { 318 Ok(pred.to_string()) 319 } else { 320 Err(()) 321 } 322 }) 323 .collect::<Result<Vec<_>, ()>>() else { return; }; 324 325 let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; }; 326 327 let suggestion = if trait_predicates.is_empty() { 328 WhereClauseSuggestions::Remove { span: generics.where_clause_span } 329 } else { 330 let space = if generics.where_clause_span.is_empty() { " " } else { "" }; 331 WhereClauseSuggestions::CopyPredicates { 332 span: generics.where_clause_span, 333 space, 334 trait_predicates: trait_predicates.join(", "), 335 } 336 }; 337 err.subdiagnostic(suggestion); 338 } 339 report_placeholder_failure( &self, placeholder_origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>340 pub(super) fn report_placeholder_failure( 341 &self, 342 placeholder_origin: SubregionOrigin<'tcx>, 343 sub: Region<'tcx>, 344 sup: Region<'tcx>, 345 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 346 // I can't think how to do better than this right now. -nikomatsakis 347 debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); 348 match placeholder_origin { 349 infer::Subtype(box ref trace) 350 if matches!( 351 &trace.cause.code().peel_derives(), 352 ObligationCauseCode::BindingObligation(..) 353 | ObligationCauseCode::ExprBindingObligation(..) 354 ) => 355 { 356 // Hack to get around the borrow checker because trace.cause has an `Rc`. 357 if let ObligationCauseCode::BindingObligation(_, span) 358 | ObligationCauseCode::ExprBindingObligation(_, span, ..) = 359 &trace.cause.code().peel_derives() 360 { 361 let span = *span; 362 let mut err = self.report_concrete_failure(placeholder_origin, sub, sup); 363 err.span_note(span, "the lifetime requirement is introduced here"); 364 err 365 } else { 366 unreachable!() 367 } 368 } 369 infer::Subtype(box trace) => { 370 let terr = TypeError::RegionsPlaceholderMismatch; 371 return self.report_and_explain_type_error(trace, terr); 372 } 373 _ => return self.report_concrete_failure(placeholder_origin, sub, sup), 374 } 375 } 376 } 377