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