1use std::iter;
2
3use rustc_data_structures::fx::FxIndexSet;
4use rustc_errors::{
5 Applicability, Diag, E0309, E0310, E0311, E0495, Subdiagnostic, struct_span_code_err,
6};
7use rustc_hir::def::DefKind;
8use rustc_hir::def_id::{DefId, LocalDefId};
9use rustc_hir::intravisit::Visitor;
10use rustc_hir::{self as hir, ParamName};
11use rustc_middle::bug;
12use rustc_middle::traits::ObligationCauseCode;
13use rustc_middle::ty::error::TypeError;
14use rustc_middle::ty::{self, IsSuggestable, Region, Ty, TyCtxt, TypeVisitableExt as _};
15use rustc_span::{BytePos, ErrorGuaranteed, Span, Symbol, kw};
16use rustc_type_ir::Upcast as _;
17use tracing::{debug, instrument};
18
19use super::ObligationCauseAsDiagArg;
20use super::nice_region_error::find_anon_type;
21use crate::error_reporting::TypeErrCtxt;
22use crate::error_reporting::infer::ObligationCauseExt;
23use crate::errors::{
24 self, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
25 RefLongerThanData, RegionOriginNote, WhereClauseSuggestions, note_and_explain,
26};
27use crate::fluent_generated as fluent;
28use crate::infer::region_constraints::GenericKind;
29use crate::infer::{self, InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin};
30
31impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
32 pub fn report_region_errors(
33 &self,
34 generic_param_scope: LocalDefId,
35 errors: &[RegionResolutionError<'tcx>],
36 ) -> ErrorGuaranteed {
37 assert!(!errors.is_empty());
38
39 if let Some(guaranteed) = self.infcx.tainted_by_errors() {
40 return guaranteed;
41 }
42
43 debug!("report_region_errors(): {} errors to start", errors.len());
44
45 let errors = self.process_errors(errors);
48
49 debug!("report_region_errors: {} errors after preprocessing", errors.len());
50
51 let mut guar = None;
52 for error in errors {
53 debug!("report_region_errors: error = {:?}", error);
54
55 let e = if let Some(guar) =
56 self.try_report_nice_region_error(generic_param_scope, &error)
57 {
58 guar
59 } else {
60 match error.clone() {
61 RegionResolutionError::ConcreteFailure(origin, sub, sup) => {
69 if sub.is_placeholder() || sup.is_placeholder() {
70 self.report_placeholder_failure(generic_param_scope, origin, sub, sup)
71 .emit()
72 } else {
73 self.report_concrete_failure(generic_param_scope, origin, sub, sup)
74 .emit()
75 }
76 }
77
78 RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => self
79 .report_generic_bound_failure(
80 generic_param_scope,
81 origin.span(),
82 Some(origin),
83 param_ty,
84 sub,
85 ),
86
87 RegionResolutionError::SubSupConflict(
88 _,
89 var_origin,
90 sub_origin,
91 sub_r,
92 sup_origin,
93 sup_r,
94 _,
95 ) => {
96 if sub_r.is_placeholder() {
97 self.report_placeholder_failure(
98 generic_param_scope,
99 sub_origin,
100 sub_r,
101 sup_r,
102 )
103 .emit()
104 } else if sup_r.is_placeholder() {
105 self.report_placeholder_failure(
106 generic_param_scope,
107 sup_origin,
108 sub_r,
109 sup_r,
110 )
111 .emit()
112 } else {
113 self.report_sub_sup_conflict(
114 generic_param_scope,
115 var_origin,
116 sub_origin,
117 sub_r,
118 sup_origin,
119 sup_r,
120 )
121 }
122 }
123
124 RegionResolutionError::UpperBoundUniverseConflict(
125 _,
126 _,
127 _,
128 sup_origin,
129 sup_r,
130 ) => {
131 assert!(sup_r.is_placeholder());
132
133 let sub_r = self.tcx.lifetimes.re_erased;
139
140 self.report_placeholder_failure(
141 generic_param_scope,
142 sup_origin,
143 sub_r,
144 sup_r,
145 )
146 .emit()
147 }
148
149 RegionResolutionError::CannotNormalize(clause, origin) => {
150 let clause: ty::Clause<'tcx> =
151 clause.map_bound(ty::ClauseKind::TypeOutlives).upcast(self.tcx);
152 self.tcx
153 .dcx()
154 .struct_span_err(origin.span(), format!("cannot normalize `{clause}`"))
155 .emit()
156 }
157 }
158 };
159
160 guar = Some(e)
161 }
162
163 guar.unwrap()
164 }
165
166 fn process_errors(
177 &self,
178 errors: &[RegionResolutionError<'tcx>],
179 ) -> Vec<RegionResolutionError<'tcx>> {
180 debug!("process_errors()");
181
182 let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e {
195 RegionResolutionError::GenericBoundFailure(..) => true,
196 RegionResolutionError::ConcreteFailure(..)
197 | RegionResolutionError::SubSupConflict(..)
198 | RegionResolutionError::UpperBoundUniverseConflict(..)
199 | RegionResolutionError::CannotNormalize(..) => false,
200 };
201
202 let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
203 errors.to_owned()
204 } else {
205 errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect()
206 };
207
208 errors.sort_by_key(|u| match *u {
210 RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
211 RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
212 RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
213 RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
214 RegionResolutionError::CannotNormalize(_, ref sro) => sro.span(),
215 });
216 errors
217 }
218
219 pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) {
220 match *origin {
221 infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
222 span: trace.cause.span,
223 requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
224 expected_found: self.values_str(trace.values, &trace.cause, err.long_ty_path()),
225 }
226 .add_to_diag(err),
227 infer::Reborrow(span) => {
228 RegionOriginNote::Plain { span, msg: fluent::trait_selection_reborrow }
229 .add_to_diag(err)
230 }
231 infer::RelateObjectBound(span) => {
232 RegionOriginNote::Plain { span, msg: fluent::trait_selection_relate_object_bound }
233 .add_to_diag(err);
234 }
235 infer::ReferenceOutlivesReferent(ty, span) => {
236 RegionOriginNote::WithName {
237 span,
238 msg: fluent::trait_selection_reference_outlives_referent,
239 name: &self.ty_to_string(ty),
240 continues: false,
241 }
242 .add_to_diag(err);
243 }
244 infer::RelateParamBound(span, ty, opt_span) => {
245 RegionOriginNote::WithName {
246 span,
247 msg: fluent::trait_selection_relate_param_bound,
248 name: &self.ty_to_string(ty),
249 continues: opt_span.is_some(),
250 }
251 .add_to_diag(err);
252 if let Some(span) = opt_span {
253 RegionOriginNote::Plain {
254 span,
255 msg: fluent::trait_selection_relate_param_bound_2,
256 }
257 .add_to_diag(err);
258 }
259 }
260 infer::RelateRegionParamBound(span, _) => {
261 RegionOriginNote::Plain {
262 span,
263 msg: fluent::trait_selection_relate_region_param_bound,
264 }
265 .add_to_diag(err);
266 }
267 infer::CompareImplItemObligation { span, .. } => {
268 RegionOriginNote::Plain {
269 span,
270 msg: fluent::trait_selection_compare_impl_item_obligation,
271 }
272 .add_to_diag(err);
273 }
274 infer::CheckAssociatedTypeBounds { ref parent, .. } => {
275 self.note_region_origin(err, parent);
276 }
277 infer::AscribeUserTypeProvePredicate(span) => {
278 RegionOriginNote::Plain {
279 span,
280 msg: fluent::trait_selection_ascribe_user_type_prove_predicate,
281 }
282 .add_to_diag(err);
283 }
284 }
285 }
286
287 pub(super) fn report_concrete_failure(
288 &self,
289 generic_param_scope: LocalDefId,
290 origin: SubregionOrigin<'tcx>,
291 sub: Region<'tcx>,
292 sup: Region<'tcx>,
293 ) -> Diag<'a> {
294 let mut err = match origin {
295 infer::Subtype(box trace) => {
296 let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
297 let mut err = self.report_and_explain_type_error(
298 trace,
299 self.tcx.param_env(generic_param_scope),
300 terr,
301 );
302 match (*sub, *sup) {
303 (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
304 (ty::RePlaceholder(_), _) => {
305 note_and_explain_region(
306 self.tcx,
307 &mut err,
308 generic_param_scope,
309 "",
310 sup,
311 " doesn't meet the lifetime requirements",
312 None,
313 );
314 }
315 (_, ty::RePlaceholder(_)) => {
316 note_and_explain_region(
317 self.tcx,
318 &mut err,
319 generic_param_scope,
320 "the required lifetime does not necessarily outlive ",
321 sub,
322 "",
323 None,
324 );
325 }
326 _ => {
327 note_and_explain_region(
328 self.tcx,
329 &mut err,
330 generic_param_scope,
331 "",
332 sup,
333 "...",
334 None,
335 );
336 note_and_explain_region(
337 self.tcx,
338 &mut err,
339 generic_param_scope,
340 "...does not necessarily outlive ",
341 sub,
342 "",
343 None,
344 );
345 }
346 }
347 err
348 }
349 infer::Reborrow(span) => {
350 let reference_valid = note_and_explain::RegionExplanation::new(
351 self.tcx,
352 generic_param_scope,
353 sub,
354 None,
355 note_and_explain::PrefixKind::RefValidFor,
356 note_and_explain::SuffixKind::Continues,
357 );
358 let content_valid = note_and_explain::RegionExplanation::new(
359 self.tcx,
360 generic_param_scope,
361 sup,
362 None,
363 note_and_explain::PrefixKind::ContentValidFor,
364 note_and_explain::SuffixKind::Empty,
365 );
366 self.dcx().create_err(OutlivesContent {
367 span,
368 notes: reference_valid.into_iter().chain(content_valid).collect(),
369 })
370 }
371 infer::RelateObjectBound(span) => {
372 let object_valid = note_and_explain::RegionExplanation::new(
373 self.tcx,
374 generic_param_scope,
375 sub,
376 None,
377 note_and_explain::PrefixKind::TypeObjValidFor,
378 note_and_explain::SuffixKind::Empty,
379 );
380 let pointer_valid = note_and_explain::RegionExplanation::new(
381 self.tcx,
382 generic_param_scope,
383 sup,
384 None,
385 note_and_explain::PrefixKind::SourcePointerValidFor,
386 note_and_explain::SuffixKind::Empty,
387 );
388 self.dcx().create_err(OutlivesBound {
389 span,
390 notes: object_valid.into_iter().chain(pointer_valid).collect(),
391 })
392 }
393 infer::RelateParamBound(span, ty, opt_span) => {
394 let prefix = match *sub {
395 ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy,
396 _ => note_and_explain::PrefixKind::TypeOutlive,
397 };
398 let suffix = if opt_span.is_some() {
399 note_and_explain::SuffixKind::ReqByBinding
400 } else {
401 note_and_explain::SuffixKind::Empty
402 };
403 let note = note_and_explain::RegionExplanation::new(
404 self.tcx,
405 generic_param_scope,
406 sub,
407 opt_span,
408 prefix,
409 suffix,
410 );
411 self.dcx().create_err(FulfillReqLifetime {
412 span,
413 ty: self.resolve_vars_if_possible(ty),
414 note,
415 })
416 }
417 infer::RelateRegionParamBound(span, ty) => {
418 let param_instantiated = note_and_explain::RegionExplanation::new(
419 self.tcx,
420 generic_param_scope,
421 sup,
422 None,
423 note_and_explain::PrefixKind::LfParamInstantiatedWith,
424 note_and_explain::SuffixKind::Empty,
425 );
426 let mut alt_span = None;
427 if let Some(ty) = ty
428 && sub.is_static()
429 && let ty::Dynamic(preds, _, ty::DynKind::Dyn) = ty.kind()
430 && let Some(def_id) = preds.principal_def_id()
431 {
432 for (clause, span) in
433 self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
434 {
435 if let ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) =
436 clause.kind().skip_binder()
437 && let ty::Param(param) = a.kind()
438 && param.name == kw::SelfUpper
439 && b.is_static()
440 {
441 alt_span = Some(span);
443 }
444 }
445 }
446 let param_must_outlive = note_and_explain::RegionExplanation::new(
447 self.tcx,
448 generic_param_scope,
449 sub,
450 alt_span,
451 note_and_explain::PrefixKind::LfParamMustOutlive,
452 note_and_explain::SuffixKind::Empty,
453 );
454 self.dcx().create_err(LfBoundNotSatisfied {
455 span,
456 notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
457 })
458 }
459 infer::ReferenceOutlivesReferent(ty, span) => {
460 let pointer_valid = note_and_explain::RegionExplanation::new(
461 self.tcx,
462 generic_param_scope,
463 sub,
464 None,
465 note_and_explain::PrefixKind::PointerValidFor,
466 note_and_explain::SuffixKind::Empty,
467 );
468 let data_valid = note_and_explain::RegionExplanation::new(
469 self.tcx,
470 generic_param_scope,
471 sup,
472 None,
473 note_and_explain::PrefixKind::DataValidFor,
474 note_and_explain::SuffixKind::Empty,
475 );
476 self.dcx().create_err(RefLongerThanData {
477 span,
478 ty: self.resolve_vars_if_possible(ty),
479 notes: pointer_valid.into_iter().chain(data_valid).collect(),
480 })
481 }
482 infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
483 let mut err = self.report_extra_impl_obligation(
484 span,
485 impl_item_def_id,
486 trait_item_def_id,
487 &format!("`{sup}: {sub}`"),
488 );
489 if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
491 && generics.where_clause_span.contains(span)
492 {
493 self.suggest_copy_trait_method_bounds(
494 trait_item_def_id,
495 impl_item_def_id,
496 &mut err,
497 );
498 }
499 err
500 }
501 infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
502 let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup);
503
504 if !self.tcx.is_impl_trait_in_trait(impl_item_def_id.to_def_id()) {
507 let trait_item_span = self.tcx.def_span(trait_item_def_id);
508 let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
509 err.span_label(
510 trait_item_span,
511 format!("definition of `{item_name}` from trait"),
512 );
513 }
514
515 self.suggest_copy_trait_method_bounds(
516 trait_item_def_id,
517 impl_item_def_id,
518 &mut err,
519 );
520 err
521 }
522 infer::AscribeUserTypeProvePredicate(span) => {
523 let instantiated = note_and_explain::RegionExplanation::new(
524 self.tcx,
525 generic_param_scope,
526 sup,
527 None,
528 note_and_explain::PrefixKind::LfInstantiatedWith,
529 note_and_explain::SuffixKind::Empty,
530 );
531 let must_outlive = note_and_explain::RegionExplanation::new(
532 self.tcx,
533 generic_param_scope,
534 sub,
535 None,
536 note_and_explain::PrefixKind::LfMustOutlive,
537 note_and_explain::SuffixKind::Empty,
538 );
539 self.dcx().create_err(LfBoundNotSatisfied {
540 span,
541 notes: instantiated.into_iter().chain(must_outlive).collect(),
542 })
543 }
544 };
545 if sub.is_error() || sup.is_error() {
546 err.downgrade_to_delayed_bug();
547 }
548 err
549 }
550
551 pub fn suggest_copy_trait_method_bounds(
552 &self,
553 trait_item_def_id: DefId,
554 impl_item_def_id: LocalDefId,
555 err: &mut Diag<'_>,
556 ) {
557 let Some(impl_def_id) = self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx)
563 else {
564 return;
565 };
566 let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) else {
567 return;
568 };
569 let trait_args = trait_ref
570 .instantiate_identity()
571 .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper))
573 .args;
574 let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id)
575 .rebase_onto(self.tcx, impl_def_id, trait_args);
576
577 let Ok(trait_predicates) =
578 self.tcx
579 .explicit_predicates_of(trait_item_def_id)
580 .instantiate_own(self.tcx, trait_item_args)
581 .map(|(pred, _)| {
582 if pred.is_suggestable(self.tcx, false) {
583 Ok(pred.to_string())
584 } else {
585 Err(())
586 }
587 })
588 .collect::<Result<Vec<_>, ()>>()
589 else {
590 return;
591 };
592
593 let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else {
594 return;
595 };
596
597 let suggestion = if trait_predicates.is_empty() {
598 WhereClauseSuggestions::Remove { span: generics.where_clause_span }
599 } else {
600 let space = if generics.where_clause_span.is_empty() { " " } else { "" };
601 WhereClauseSuggestions::CopyPredicates {
602 span: generics.where_clause_span,
603 space,
604 trait_predicates: trait_predicates.join(", "),
605 }
606 };
607 err.subdiagnostic(suggestion);
608 }
609
610 pub(super) fn report_placeholder_failure(
611 &self,
612 generic_param_scope: LocalDefId,
613 placeholder_origin: SubregionOrigin<'tcx>,
614 sub: Region<'tcx>,
615 sup: Region<'tcx>,
616 ) -> Diag<'a> {
617 debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
619 match placeholder_origin {
620 infer::Subtype(box ref trace)
621 if matches!(
622 &trace.cause.code().peel_derives(),
623 ObligationCauseCode::WhereClause(..)
624 | ObligationCauseCode::WhereClauseInExpr(..)
625 ) =>
626 {
627 if let ObligationCauseCode::WhereClause(_, span)
629 | ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
630 &trace.cause.code().peel_derives()
631 {
632 let span = *span;
633 let mut err = self.report_concrete_failure(
634 generic_param_scope,
635 placeholder_origin,
636 sub,
637 sup,
638 );
639 if !span.is_dummy() {
640 err =
641 err.with_span_note(span, "the lifetime requirement is introduced here");
642 }
643 err
644 } else {
645 unreachable!(
646 "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..."
647 )
648 }
649 }
650 infer::Subtype(box trace) => {
651 let terr = TypeError::RegionsPlaceholderMismatch;
652 return self.report_and_explain_type_error(
653 trace,
654 self.tcx.param_env(generic_param_scope),
655 terr,
656 );
657 }
658 _ => {
659 return self.report_concrete_failure(
660 generic_param_scope,
661 placeholder_origin,
662 sub,
663 sup,
664 );
665 }
666 }
667 }
668
669 pub fn report_generic_bound_failure(
670 &self,
671 generic_param_scope: LocalDefId,
672 span: Span,
673 origin: Option<SubregionOrigin<'tcx>>,
674 bound_kind: GenericKind<'tcx>,
675 sub: Region<'tcx>,
676 ) -> ErrorGuaranteed {
677 self.construct_generic_bound_failure(generic_param_scope, span, origin, bound_kind, sub)
678 .emit()
679 }
680
681 pub fn construct_generic_bound_failure(
682 &self,
683 generic_param_scope: LocalDefId,
684 span: Span,
685 origin: Option<SubregionOrigin<'tcx>>,
686 bound_kind: GenericKind<'tcx>,
687 sub: Region<'tcx>,
688 ) -> Diag<'a> {
689 if let Some(SubregionOrigin::CompareImplItemObligation {
690 span,
691 impl_item_def_id,
692 trait_item_def_id,
693 }) = origin
694 {
695 return self.report_extra_impl_obligation(
696 span,
697 impl_item_def_id,
698 trait_item_def_id,
699 &format!("`{bound_kind}: {sub}`"),
700 );
701 }
702
703 let labeled_user_string = match bound_kind {
704 GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
705 GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
706 GenericKind::Alias(ref p) => match p.kind(self.tcx) {
707 ty::Projection | ty::Inherent => {
708 format!("the associated type `{p}`")
709 }
710 ty::Weak => format!("the type alias `{p}`"),
711 ty::Opaque => format!("the opaque type `{p}`"),
712 },
713 };
714
715 let mut err = self
716 .tcx
717 .dcx()
718 .struct_span_err(span, format!("{labeled_user_string} may not live long enough"));
719 err.code(match sub.kind() {
720 ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => E0309,
721 ty::ReStatic => E0310,
722 _ => E0311,
723 });
724
725 '_explain: {
726 let (description, span) = match sub.kind() {
727 ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
728 msg_span_from_named_region(self.tcx, generic_param_scope, sub, Some(span))
729 }
730 _ => (format!("lifetime `{sub}`"), Some(span)),
731 };
732 let prefix = format!("{labeled_user_string} must be valid for ");
733 label_msg_span(&mut err, &prefix, description, span, "...");
734 if let Some(origin) = origin {
735 self.note_region_origin(&mut err, &origin);
736 }
737 }
738
739 'suggestion: {
740 let msg = "consider adding an explicit lifetime bound";
741
742 if (bound_kind, sub).has_infer_regions()
743 || (bound_kind, sub).has_placeholders()
744 || !bound_kind.is_suggestable(self.tcx, false)
745 {
746 let lt_name = sub.get_name_or_anon().to_string();
747 err.help(format!("{msg} `{bound_kind}: {lt_name}`..."));
748 break 'suggestion;
749 }
750
751 let mut generic_param_scope = generic_param_scope;
752 while self.tcx.def_kind(generic_param_scope) == DefKind::OpaqueTy {
753 generic_param_scope = self.tcx.local_parent(generic_param_scope);
754 }
755
756 let (type_scope, type_param_sugg_span) = match bound_kind {
758 GenericKind::Param(param) => {
759 let generics = self.tcx.generics_of(generic_param_scope);
760 let type_param = generics.type_param(param, self.tcx);
761 let def_id = type_param.def_id.expect_local();
762 let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id;
763 let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
767 let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
768 Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)),
769 None if generics.has_self && param.index == 0 => None,
771 None => {
772 let span = if let Some(param) =
773 hir_generics.params.iter().find(|param| param.def_id == def_id)
774 && let ParamName::Plain(ident) = param.name
775 {
776 ident.span.shrink_to_hi()
777 } else {
778 let span = self.tcx.def_span(def_id);
779 span.shrink_to_hi()
780 };
781 Some((span, false, None))
782 }
783 };
784 (scope, sugg_span)
785 }
786 _ => (generic_param_scope, None),
787 };
788 let suggestion_scope = {
789 let lifetime_scope = match sub.kind() {
790 ty::ReStatic => hir::def_id::CRATE_DEF_ID,
791 _ => match self.tcx.is_suitable_region(generic_param_scope, sub) {
792 Some(info) => info.scope,
793 None => generic_param_scope,
794 },
795 };
796 match self.tcx.is_descendant_of(type_scope.into(), lifetime_scope.into()) {
797 true => type_scope,
798 false => lifetime_scope,
799 }
800 };
801
802 let mut suggs = vec![];
803 let lt_name = self.suggest_name_region(generic_param_scope, sub, &mut suggs);
804
805 if let Some((sp, has_lifetimes, open_paren_sp)) = type_param_sugg_span
806 && suggestion_scope == type_scope
807 {
808 let suggestion =
809 if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
810
811 if let Some(open_paren_sp) = open_paren_sp {
812 suggs.push((open_paren_sp, "(".to_string()));
813 suggs.push((sp, format!("){suggestion}")));
814 } else {
815 suggs.push((sp, suggestion))
816 }
817 } else if let GenericKind::Alias(ref p) = bound_kind
818 && let ty::Projection = p.kind(self.tcx)
819 && let DefKind::AssocTy = self.tcx.def_kind(p.def_id)
820 && let Some(ty::ImplTraitInTraitData::Trait { .. }) =
821 self.tcx.opt_rpitit_info(p.def_id)
822 {
823 } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) {
826 let pred = format!("{bound_kind}: {lt_name}");
827 let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred);
828 suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion))
829 } else {
830 let consider = format!("{msg} `{bound_kind}: {sub}`...");
831 err.help(consider);
832 }
833
834 if !suggs.is_empty() {
835 err.multipart_suggestion_verbose(
836 msg,
837 suggs,
838 Applicability::MaybeIncorrect, );
840 }
841 }
842
843 err
844 }
845
846 pub fn suggest_name_region(
847 &self,
848 generic_param_scope: LocalDefId,
849 lifetime: Region<'tcx>,
850 add_lt_suggs: &mut Vec<(Span, String)>,
851 ) -> String {
852 struct LifetimeReplaceVisitor<'a> {
853 needle: hir::LifetimeName,
854 new_lt: &'a str,
855 add_lt_suggs: &'a mut Vec<(Span, String)>,
856 }
857
858 impl<'hir> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_> {
859 fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
860 if lt.res == self.needle {
861 self.add_lt_suggs.push(lt.suggestion(self.new_lt));
862 }
863 }
864 }
865
866 let (lifetime_def_id, lifetime_scope) = match self
867 .tcx
868 .is_suitable_region(generic_param_scope, lifetime)
869 {
870 Some(info) if !lifetime.has_name() => (info.region_def_id.expect_local(), info.scope),
871 _ => return lifetime.get_name_or_anon().to_string(),
872 };
873
874 let new_lt = {
875 let generics = self.tcx.generics_of(lifetime_scope);
876 let mut used_names =
877 iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
878 .flat_map(|g| &g.own_params)
879 .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
880 .map(|p| p.name)
881 .collect::<Vec<_>>();
882 let hir_id = self.tcx.local_def_id_to_hir_id(lifetime_scope);
883 used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(
885 |p| match p {
886 ty::BoundVariableKind::Region(lt) => lt.get_name(),
887 _ => None,
888 },
889 ));
890 (b'a'..=b'z')
891 .map(|c| format!("'{}", c as char))
892 .find(|candidate| !used_names.iter().any(|e| e.as_str() == candidate))
893 .unwrap_or("'lt".to_string())
894 };
895
896 let mut visitor = LifetimeReplaceVisitor {
897 needle: hir::LifetimeName::Param(lifetime_def_id),
898 add_lt_suggs,
899 new_lt: &new_lt,
900 };
901 match self.tcx.expect_hir_owner_node(lifetime_scope) {
902 hir::OwnerNode::Item(i) => visitor.visit_item(i),
903 hir::OwnerNode::ForeignItem(i) => visitor.visit_foreign_item(i),
904 hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i),
905 hir::OwnerNode::TraitItem(i) => visitor.visit_trait_item(i),
906 hir::OwnerNode::Crate(_) => bug!("OwnerNode::Crate doesn't not have generics"),
907 hir::OwnerNode::Synthetic => unreachable!(),
908 }
909
910 let ast_generics = self.tcx.hir().get_generics(lifetime_scope).unwrap();
911 let sugg = ast_generics
912 .span_for_lifetime_suggestion()
913 .map(|span| (span, format!("{new_lt}, ")))
914 .unwrap_or_else(|| (ast_generics.span, format!("<{new_lt}>")));
915 add_lt_suggs.push(sugg);
916
917 new_lt
918 }
919
920 fn report_sub_sup_conflict(
921 &self,
922 generic_param_scope: LocalDefId,
923 var_origin: RegionVariableOrigin,
924 sub_origin: SubregionOrigin<'tcx>,
925 sub_region: Region<'tcx>,
926 sup_origin: SubregionOrigin<'tcx>,
927 sup_region: Region<'tcx>,
928 ) -> ErrorGuaranteed {
929 let mut err = self.report_inference_failure(var_origin);
930
931 note_and_explain_region(
932 self.tcx,
933 &mut err,
934 generic_param_scope,
935 "first, the lifetime cannot outlive ",
936 sup_region,
937 "...",
938 None,
939 );
940
941 debug!("report_sub_sup_conflict: var_origin={:?}", var_origin);
942 debug!("report_sub_sup_conflict: sub_region={:?}", sub_region);
943 debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin);
944 debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
945 debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
946
947 if let infer::Subtype(ref sup_trace) = sup_origin
948 && let infer::Subtype(ref sub_trace) = sub_origin
949 && let Some((sup_expected, sup_found)) =
950 self.values_str(sup_trace.values, &sup_trace.cause, err.long_ty_path())
951 && let Some((sub_expected, sub_found)) =
952 self.values_str(sub_trace.values, &sup_trace.cause, err.long_ty_path())
953 && sub_expected == sup_expected
954 && sub_found == sup_found
955 {
956 note_and_explain_region(
957 self.tcx,
958 &mut err,
959 generic_param_scope,
960 "...but the lifetime must also be valid for ",
961 sub_region,
962 "...",
963 None,
964 );
965 err.span_note(
966 sup_trace.cause.span,
967 format!("...so that the {}", sup_trace.cause.as_requirement_str()),
968 );
969
970 err.note_expected_found(&"", sup_expected, &"", sup_found);
971 return if sub_region.is_error() | sup_region.is_error() {
972 err.delay_as_bug()
973 } else {
974 err.emit()
975 };
976 }
977
978 self.note_region_origin(&mut err, &sup_origin);
979
980 note_and_explain_region(
981 self.tcx,
982 &mut err,
983 generic_param_scope,
984 "but, the lifetime must be valid for ",
985 sub_region,
986 "...",
987 None,
988 );
989
990 self.note_region_origin(&mut err, &sub_origin);
991 if sub_region.is_error() | sup_region.is_error() { err.delay_as_bug() } else { err.emit() }
992 }
993
994 fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> {
995 let br_string = |br: ty::BoundRegionKind| {
996 let mut s = match br {
997 ty::BoundRegionKind::Named(_, name) => name.to_string(),
998 _ => String::new(),
999 };
1000 if !s.is_empty() {
1001 s.push(' ');
1002 }
1003 s
1004 };
1005 let var_description = match var_origin {
1006 infer::MiscVariable(_) => String::new(),
1007 infer::PatternRegion(_) => " for pattern".to_string(),
1008 infer::BorrowRegion(_) => " for borrow expression".to_string(),
1009 infer::Autoref(_) => " for autoref".to_string(),
1010 infer::Coercion(_) => " for automatic coercion".to_string(),
1011 infer::BoundRegion(_, br, infer::FnCall) => {
1012 format!(" for lifetime parameter {}in function call", br_string(br))
1013 }
1014 infer::BoundRegion(_, br, infer::HigherRankedType) => {
1015 format!(" for lifetime parameter {}in generic type", br_string(br))
1016 }
1017 infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
1018 " for lifetime parameter {}in trait containing associated type `{}`",
1019 br_string(br),
1020 self.tcx.associated_item(def_id).name
1021 ),
1022 infer::RegionParameterDefinition(_, name) => {
1023 format!(" for lifetime parameter `{name}`")
1024 }
1025 infer::UpvarRegion(ref upvar_id, _) => {
1026 let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
1027 format!(" for capture of `{var_name}` by closure")
1028 }
1029 infer::Nll(..) => bug!("NLL variable found in lexical phase"),
1030 };
1031
1032 struct_span_code_err!(
1033 self.dcx(),
1034 var_origin.span(),
1035 E0495,
1036 "cannot infer an appropriate lifetime{} due to conflicting requirements",
1037 var_description
1038 )
1039 }
1040}
1041
1042pub(super) fn note_and_explain_region<'tcx>(
1043 tcx: TyCtxt<'tcx>,
1044 err: &mut Diag<'_>,
1045 generic_param_scope: LocalDefId,
1046 prefix: &str,
1047 region: ty::Region<'tcx>,
1048 suffix: &str,
1049 alt_span: Option<Span>,
1050) {
1051 let (description, span) = match *region {
1052 ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReStatic => {
1053 msg_span_from_named_region(tcx, generic_param_scope, region, alt_span)
1054 }
1055
1056 ty::ReError(_) => return,
1057
1058 ty::ReVar(_) => (format!("lifetime `{region}`"), alt_span),
1060
1061 ty::ReBound(..) | ty::ReErased => {
1062 bug!("unexpected region for note_and_explain_region: {:?}", region);
1063 }
1064 };
1065
1066 emit_msg_span(err, prefix, description, span, suffix);
1067}
1068
1069fn explain_free_region<'tcx>(
1070 tcx: TyCtxt<'tcx>,
1071 err: &mut Diag<'_>,
1072 generic_param_scope: LocalDefId,
1073 prefix: &str,
1074 region: ty::Region<'tcx>,
1075 suffix: &str,
1076) {
1077 let (description, span) = msg_span_from_named_region(tcx, generic_param_scope, region, None);
1078
1079 label_msg_span(err, prefix, description, span, suffix);
1080}
1081
1082fn msg_span_from_named_region<'tcx>(
1083 tcx: TyCtxt<'tcx>,
1084 generic_param_scope: LocalDefId,
1085 region: ty::Region<'tcx>,
1086 alt_span: Option<Span>,
1087) -> (String, Option<Span>) {
1088 match *region {
1089 ty::ReEarlyParam(br) => {
1090 let param_def_id = tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id;
1091 let span = tcx.def_span(param_def_id);
1092 let text = if br.has_name() {
1093 format!("the lifetime `{}` as defined here", br.name)
1094 } else {
1095 "the anonymous lifetime as defined here".to_string()
1096 };
1097 (text, Some(span))
1098 }
1099 ty::ReLateParam(ref fr) => {
1100 if !fr.kind.is_named()
1101 && let Some((ty, _)) = find_anon_type(tcx, generic_param_scope, region)
1102 {
1103 ("the anonymous lifetime defined here".to_string(), Some(ty.span))
1104 } else {
1105 match fr.kind {
1106 ty::LateParamRegionKind::Named(param_def_id, name) => {
1107 let span = tcx.def_span(param_def_id);
1108 let text = if name == kw::UnderscoreLifetime {
1109 "the anonymous lifetime as defined here".to_string()
1110 } else {
1111 format!("the lifetime `{name}` as defined here")
1112 };
1113 (text, Some(span))
1114 }
1115 ty::LateParamRegionKind::Anon(_) => (
1116 "the anonymous lifetime as defined here".to_string(),
1117 Some(tcx.def_span(generic_param_scope)),
1118 ),
1119 _ => (
1120 format!("the lifetime `{region}` as defined here"),
1121 Some(tcx.def_span(generic_param_scope)),
1122 ),
1123 }
1124 }
1125 }
1126 ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
1127 ty::RePlaceholder(ty::PlaceholderRegion {
1128 bound: ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id, name), .. },
1129 ..
1130 }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))),
1131 ty::RePlaceholder(ty::PlaceholderRegion {
1132 bound: ty::BoundRegion { kind: ty::BoundRegionKind::Anon, .. },
1133 ..
1134 }) => ("an anonymous lifetime".to_owned(), None),
1135 _ => bug!("{:?}", region),
1136 }
1137}
1138
1139fn emit_msg_span(
1140 err: &mut Diag<'_>,
1141 prefix: &str,
1142 description: String,
1143 span: Option<Span>,
1144 suffix: &str,
1145) {
1146 let message = format!("{prefix}{description}{suffix}");
1147
1148 if let Some(span) = span {
1149 err.span_note(span, message);
1150 } else {
1151 err.note(message);
1152 }
1153}
1154
1155fn label_msg_span(
1156 err: &mut Diag<'_>,
1157 prefix: &str,
1158 description: String,
1159 span: Option<Span>,
1160 suffix: &str,
1161) {
1162 let message = format!("{prefix}{description}{suffix}");
1163
1164 if let Some(span) = span {
1165 err.span_label(span, message);
1166 } else {
1167 err.note(message);
1168 }
1169}
1170
1171#[instrument(level = "trace", skip(infcx))]
1172pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
1173 infcx: &'a InferCtxt<'tcx>,
1174 generic_param_scope: LocalDefId,
1175 span: Span,
1176 hidden_ty: Ty<'tcx>,
1177 hidden_region: ty::Region<'tcx>,
1178 opaque_ty_key: ty::OpaqueTypeKey<'tcx>,
1179) -> Diag<'a> {
1180 let tcx = infcx.tcx;
1181 let mut err = infcx.dcx().create_err(errors::OpaqueCapturesLifetime {
1182 span,
1183 opaque_ty: Ty::new_opaque(tcx, opaque_ty_key.def_id.to_def_id(), opaque_ty_key.args),
1184 opaque_ty_span: tcx.def_span(opaque_ty_key.def_id),
1185 });
1186
1187 match *hidden_region {
1189 ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
1190 explain_free_region(
1199 tcx,
1200 &mut err,
1201 generic_param_scope,
1202 &format!("hidden type `{hidden_ty}` captures "),
1203 hidden_region,
1204 "",
1205 );
1206 if let Some(_) = tcx.is_suitable_region(generic_param_scope, hidden_region) {
1207 suggest_precise_capturing(tcx, opaque_ty_key.def_id, hidden_region, &mut err);
1208 }
1209 }
1210 ty::RePlaceholder(_) => {
1211 explain_free_region(
1212 tcx,
1213 &mut err,
1214 generic_param_scope,
1215 &format!("hidden type `{}` captures ", hidden_ty),
1216 hidden_region,
1217 "",
1218 );
1219 }
1220 ty::ReError(_) => {
1221 err.downgrade_to_delayed_bug();
1222 }
1223 _ => {
1224 note_and_explain_region(
1240 tcx,
1241 &mut err,
1242 generic_param_scope,
1243 &format!("hidden type `{hidden_ty}` captures "),
1244 hidden_region,
1245 "",
1246 None,
1247 );
1248 }
1249 }
1250
1251 err
1252}
1253
1254fn suggest_precise_capturing<'tcx>(
1255 tcx: TyCtxt<'tcx>,
1256 opaque_def_id: LocalDefId,
1257 captured_lifetime: ty::Region<'tcx>,
1258 diag: &mut Diag<'_>,
1259) {
1260 let hir::OpaqueTy { bounds, origin, .. } =
1261 tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
1262
1263 let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } = *origin else {
1264 return;
1265 };
1266
1267 let new_lifetime = Symbol::intern(&captured_lifetime.to_string());
1268
1269 if let Some((args, span)) = bounds.iter().find_map(|bound| match bound {
1270 hir::GenericBound::Use(args, span) => Some((args, span)),
1271 _ => None,
1272 }) {
1273 let last_lifetime_span = args.iter().rev().find_map(|arg| match arg {
1274 hir::PreciseCapturingArg::Lifetime(lt) => Some(lt.ident.span),
1275 _ => None,
1276 });
1277
1278 let first_param_span = args.iter().find_map(|arg| match arg {
1279 hir::PreciseCapturingArg::Param(p) => Some(p.ident.span),
1280 _ => None,
1281 });
1282
1283 let (span, pre, post) = if let Some(last_lifetime_span) = last_lifetime_span {
1284 (last_lifetime_span.shrink_to_hi(), ", ", "")
1285 } else if let Some(first_param_span) = first_param_span {
1286 (first_param_span.shrink_to_lo(), "", ", ")
1287 } else {
1288 (span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), "", "")
1292 };
1293
1294 diag.subdiagnostic(errors::AddPreciseCapturing::Existing { span, new_lifetime, pre, post });
1295 } else {
1296 let mut captured_lifetimes = FxIndexSet::default();
1297 let mut captured_non_lifetimes = FxIndexSet::default();
1298
1299 let variances = tcx.variances_of(opaque_def_id);
1300 let mut generics = tcx.generics_of(opaque_def_id);
1301 let mut synthetics = vec![];
1302 loop {
1303 for param in &generics.own_params {
1304 if variances[param.index as usize] == ty::Bivariant {
1305 continue;
1306 }
1307
1308 match param.kind {
1309 ty::GenericParamDefKind::Lifetime => {
1310 captured_lifetimes.insert(param.name);
1311 }
1312 ty::GenericParamDefKind::Type { synthetic: true, .. } => {
1313 synthetics.push((tcx.def_span(param.def_id), param.name));
1314 }
1315 ty::GenericParamDefKind::Type { .. }
1316 | ty::GenericParamDefKind::Const { .. } => {
1317 captured_non_lifetimes.insert(param.name);
1318 }
1319 }
1320 }
1321
1322 if let Some(parent) = generics.parent {
1323 generics = tcx.generics_of(parent);
1324 } else {
1325 break;
1326 }
1327 }
1328
1329 if !captured_lifetimes.insert(new_lifetime) {
1330 return;
1332 }
1333
1334 if synthetics.is_empty() {
1335 let concatenated_bounds = captured_lifetimes
1336 .into_iter()
1337 .chain(captured_non_lifetimes)
1338 .map(|sym| sym.to_string())
1339 .collect::<Vec<_>>()
1340 .join(", ");
1341
1342 diag.subdiagnostic(errors::AddPreciseCapturing::New {
1343 span: tcx.def_span(opaque_def_id).shrink_to_hi(),
1344 new_lifetime,
1345 concatenated_bounds,
1346 });
1347 } else {
1348 let mut next_fresh_param = || {
1349 ["T", "U", "V", "W", "X", "Y", "A", "B", "C"]
1350 .into_iter()
1351 .map(Symbol::intern)
1352 .chain((0..).map(|i| Symbol::intern(&format!("T{i}"))))
1353 .find(|s| captured_non_lifetimes.insert(*s))
1354 .unwrap()
1355 };
1356
1357 let mut new_params = String::new();
1358 let mut suggs = vec![];
1359 let mut apit_spans = vec![];
1360
1361 for (i, (span, name)) in synthetics.into_iter().enumerate() {
1362 apit_spans.push(span);
1363
1364 let fresh_param = next_fresh_param();
1365
1366 suggs.push((span, fresh_param.to_string()));
1368
1369 if i > 0 {
1377 new_params += ", ";
1378 }
1379 let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start();
1380 new_params += fresh_param.as_str();
1381 new_params += ": ";
1382 new_params += name_as_bounds;
1383 }
1384
1385 let Some(generics) = tcx.hir().get_generics(fn_def_id) else {
1386 return;
1388 };
1389
1390 suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() {
1392 (params_span, format!(", {new_params}"))
1393 } else {
1394 (generics.span, format!("<{new_params}>"))
1395 });
1396
1397 let concatenated_bounds = captured_lifetimes
1398 .into_iter()
1399 .chain(captured_non_lifetimes)
1400 .map(|sym| sym.to_string())
1401 .collect::<Vec<_>>()
1402 .join(", ");
1403
1404 suggs.push((
1405 tcx.def_span(opaque_def_id).shrink_to_hi(),
1406 format!(" + use<{concatenated_bounds}>"),
1407 ));
1408
1409 diag.subdiagnostic(errors::AddPreciseCapturingAndParams {
1410 suggs,
1411 new_lifetime,
1412 apit_spans,
1413 });
1414 }
1415 }
1416}