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