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.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.trait_impl_of_assoc(impl_item_def_id.to_def_id()) else {
575 return;
576 };
577 let trait_ref = self.tcx.impl_trait_ref(impl_def_id);
578 let trait_args = trait_ref
579 .instantiate_identity()
580 .with_replaced_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper))
582 .args;
583 let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id)
584 .rebase_onto(self.tcx, impl_def_id, trait_args);
585
586 let Ok(trait_predicates) =
587 self.tcx
588 .explicit_predicates_of(trait_item_def_id)
589 .instantiate_own(self.tcx, trait_item_args)
590 .map(|(pred, _)| {
591 if pred.is_suggestable(self.tcx, false) {
592 Ok(pred.to_string())
593 } else {
594 Err(())
595 }
596 })
597 .collect::<Result<Vec<_>, ()>>()
598 else {
599 return;
600 };
601
602 let Some(generics) = self.tcx.hir_get_generics(impl_item_def_id) else {
603 return;
604 };
605
606 let suggestion = if trait_predicates.is_empty() {
607 WhereClauseSuggestions::Remove { span: generics.where_clause_span }
608 } else {
609 let space = if generics.where_clause_span.is_empty() { " " } else { "" };
610 WhereClauseSuggestions::CopyPredicates {
611 span: generics.where_clause_span,
612 space,
613 trait_predicates: trait_predicates.join(", "),
614 }
615 };
616 err.subdiagnostic(suggestion);
617 }
618
619 pub(super) fn report_placeholder_failure(
620 &self,
621 generic_param_scope: LocalDefId,
622 placeholder_origin: SubregionOrigin<'tcx>,
623 sub: Region<'tcx>,
624 sup: Region<'tcx>,
625 ) -> Diag<'a> {
626 debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
628 match placeholder_origin {
629 SubregionOrigin::Subtype(box ref trace)
630 if matches!(
631 &trace.cause.code().peel_derives(),
632 ObligationCauseCode::WhereClause(..)
633 | ObligationCauseCode::WhereClauseInExpr(..)
634 ) =>
635 {
636 if let ObligationCauseCode::WhereClause(_, span)
638 | ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
639 &trace.cause.code().peel_derives()
640 {
641 let span = *span;
642 let mut err = self.report_concrete_failure(
643 generic_param_scope,
644 placeholder_origin,
645 sub,
646 sup,
647 );
648 if !span.is_dummy() {
649 err =
650 err.with_span_note(span, "the lifetime requirement is introduced here");
651 }
652 err
653 } else {
654 unreachable!(
655 "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..."
656 )
657 }
658 }
659 SubregionOrigin::Subtype(box trace) => {
660 let terr = TypeError::RegionsPlaceholderMismatch;
661 return self.report_and_explain_type_error(
662 trace,
663 self.tcx.param_env(generic_param_scope),
664 terr,
665 );
666 }
667 _ => {
668 return self.report_concrete_failure(
669 generic_param_scope,
670 placeholder_origin,
671 sub,
672 sup,
673 );
674 }
675 }
676 }
677
678 pub fn report_generic_bound_failure(
679 &self,
680 generic_param_scope: LocalDefId,
681 span: Span,
682 origin: Option<SubregionOrigin<'tcx>>,
683 bound_kind: GenericKind<'tcx>,
684 sub: Region<'tcx>,
685 ) -> ErrorGuaranteed {
686 self.construct_generic_bound_failure(generic_param_scope, span, origin, bound_kind, sub)
687 .emit()
688 }
689
690 pub fn construct_generic_bound_failure(
691 &self,
692 generic_param_scope: LocalDefId,
693 span: Span,
694 origin: Option<SubregionOrigin<'tcx>>,
695 bound_kind: GenericKind<'tcx>,
696 sub: Region<'tcx>,
697 ) -> Diag<'a> {
698 if let Some(SubregionOrigin::CompareImplItemObligation {
699 span,
700 impl_item_def_id,
701 trait_item_def_id,
702 }) = origin
703 {
704 return self.report_extra_impl_obligation(
705 span,
706 impl_item_def_id,
707 trait_item_def_id,
708 &format!("`{bound_kind}: {sub}`"),
709 );
710 }
711
712 let labeled_user_string = match bound_kind {
713 GenericKind::Param(_) => format!("the parameter type `{bound_kind}`"),
714 GenericKind::Placeholder(_) => format!("the placeholder type `{bound_kind}`"),
715 GenericKind::Alias(p) => match p.kind(self.tcx) {
716 ty::Projection | ty::Inherent => {
717 format!("the associated type `{bound_kind}`")
718 }
719 ty::Free => format!("the type alias `{bound_kind}`"),
720 ty::Opaque => format!("the opaque type `{bound_kind}`"),
721 },
722 };
723
724 let mut err = self
725 .tcx
726 .dcx()
727 .struct_span_err(span, format!("{labeled_user_string} may not live long enough"));
728 err.code(match sub.kind() {
729 ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.is_named(self.tcx) => E0309,
730 ty::ReStatic => E0310,
731 _ => E0311,
732 });
733
734 '_explain: {
735 let (description, span) = match sub.kind() {
736 ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
737 msg_span_from_named_region(self.tcx, generic_param_scope, sub, Some(span))
738 }
739 _ => (format!("lifetime `{sub}`"), Some(span)),
740 };
741 let prefix = format!("{labeled_user_string} must be valid for ");
742 label_msg_span(&mut err, &prefix, description, span, "...");
743 if let Some(origin) = origin {
744 self.note_region_origin(&mut err, &origin);
745 }
746 }
747
748 'suggestion: {
749 let msg = "consider adding an explicit lifetime bound";
750
751 if (bound_kind, sub).has_infer_regions()
752 || (bound_kind, sub).has_placeholders()
753 || !bound_kind.is_suggestable(self.tcx, false)
754 {
755 let lt_name = sub.get_name_or_anon(self.tcx).to_string();
756 err.help(format!("{msg} `{bound_kind}: {lt_name}`..."));
757 break 'suggestion;
758 }
759
760 let mut generic_param_scope = generic_param_scope;
761 while self.tcx.def_kind(generic_param_scope) == DefKind::OpaqueTy {
762 generic_param_scope = self.tcx.local_parent(generic_param_scope);
763 }
764
765 let (type_scope, type_param_sugg_span) = match bound_kind {
767 GenericKind::Param(param) => {
768 let generics = self.tcx.generics_of(generic_param_scope);
769 let type_param = generics.type_param(param, self.tcx);
770 let def_id = type_param.def_id.expect_local();
771 let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id;
772 let hir_generics = self.tcx.hir_get_generics(scope).unwrap();
776 let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
777 Some((span, open_paren_sp)) => {
778 Some((span, LifetimeSuggestion::NeedsPlus(open_paren_sp)))
779 }
780 None if generics.has_self && param.index == 0 => None,
782 None => {
783 let mut colon_flag = false;
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 if let Some(sp) = param.colon_span {
789 colon_flag = true;
790 sp.shrink_to_hi()
791 } else {
792 ident.span.shrink_to_hi()
793 }
794 } else {
795 let span = self.tcx.def_span(def_id);
796 span.shrink_to_hi()
797 };
798 match colon_flag {
799 true => Some((span, LifetimeSuggestion::HasColon)),
800 false => Some((span, LifetimeSuggestion::NeedsColon)),
801 }
802 }
803 };
804 (scope, sugg_span)
805 }
806 _ => (generic_param_scope, None),
807 };
808 let suggestion_scope = {
809 let lifetime_scope = match sub.kind() {
810 ty::ReStatic => hir::def_id::CRATE_DEF_ID,
811 _ => match self.tcx.is_suitable_region(generic_param_scope, sub) {
812 Some(info) => info.scope,
813 None => generic_param_scope,
814 },
815 };
816 match self.tcx.is_descendant_of(type_scope.into(), lifetime_scope.into()) {
817 true => type_scope,
818 false => lifetime_scope,
819 }
820 };
821
822 let mut suggs = vec![];
823 let lt_name = self.suggest_name_region(generic_param_scope, sub, &mut suggs);
824
825 if let Some((sp, suggestion_type)) = type_param_sugg_span
826 && suggestion_scope == type_scope
827 {
828 match suggestion_type {
829 LifetimeSuggestion::NeedsPlus(open_paren_sp) => {
830 let suggestion = format!(" + {lt_name}");
831 if let Some(open_paren_sp) = open_paren_sp {
832 suggs.push((open_paren_sp, "(".to_string()));
833 suggs.push((sp, format!("){suggestion}")));
834 } else {
835 suggs.push((sp, suggestion));
836 }
837 }
838 LifetimeSuggestion::NeedsColon => suggs.push((sp, format!(": {lt_name}"))),
839 LifetimeSuggestion::HasColon => suggs.push((sp, format!(" {lt_name}"))),
840 }
841 } else if let GenericKind::Alias(ref p) = bound_kind
842 && let ty::Projection = p.kind(self.tcx)
843 && let DefKind::AssocTy = self.tcx.def_kind(p.def_id)
844 && let Some(ty::ImplTraitInTraitData::Trait { .. }) =
845 self.tcx.opt_rpitit_info(p.def_id)
846 {
847 } else if let Some(generics) = self.tcx.hir_get_generics(suggestion_scope) {
850 let pred = format!("{bound_kind}: {lt_name}");
851 let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred);
852 suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion))
853 } else {
854 let consider = format!("{msg} `{bound_kind}: {sub}`...");
855 err.help(consider);
856 }
857
858 if !suggs.is_empty() {
859 err.multipart_suggestion_verbose(
860 msg,
861 suggs,
862 Applicability::MaybeIncorrect, );
864 }
865 }
866
867 if sub.kind() == ty::ReStatic
868 && let Some(node) = self.tcx.hir_get_if_local(generic_param_scope.into())
869 && let hir::Node::Item(hir::Item {
870 kind: hir::ItemKind::Fn { sig, body, has_body: true, .. },
871 ..
872 })
873 | hir::Node::TraitItem(hir::TraitItem {
874 kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body)),
875 ..
876 })
877 | hir::Node::ImplItem(hir::ImplItem {
878 kind: hir::ImplItemKind::Fn(sig, body), ..
879 }) = node
880 && let hir::Node::Expr(expr) = self.tcx.hir_node(body.hir_id)
881 && let hir::ExprKind::Block(block, _) = expr.kind
882 && let Some(tail) = block.expr
883 && tail.span == span
884 && let hir::FnRetTy::Return(ty) = sig.decl.output
885 && let hir::TyKind::Path(path) = ty.kind
886 && let hir::QPath::Resolved(None, path) = path
887 && let hir::def::Res::Def(_, def_id) = path.res
888 && Some(def_id) == self.tcx.lang_items().owned_box()
889 && let [segment] = path.segments
890 && let Some(args) = segment.args
891 && let [hir::GenericArg::Type(ty)] = args.args
892 && let hir::TyKind::TraitObject(_, tagged_ref) = ty.kind
893 && let hir::LifetimeKind::ImplicitObjectLifetimeDefault = tagged_ref.pointer().kind
894 {
895 err.span_label(
898 ty.span,
899 format!("this `dyn Trait` has an implicit `'static` lifetime bound"),
900 );
901 }
902
903 err
904 }
905
906 pub fn suggest_name_region(
907 &self,
908 generic_param_scope: LocalDefId,
909 lifetime: Region<'tcx>,
910 add_lt_suggs: &mut Vec<(Span, String)>,
911 ) -> String {
912 struct LifetimeReplaceVisitor<'a> {
913 needle: hir::LifetimeKind,
914 new_lt: &'a str,
915 add_lt_suggs: &'a mut Vec<(Span, String)>,
916 }
917
918 impl<'hir> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_> {
919 fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
920 if lt.kind == self.needle {
921 self.add_lt_suggs.push(lt.suggestion(self.new_lt));
922 }
923 }
924 }
925
926 let (lifetime_def_id, lifetime_scope) =
927 match self.tcx.is_suitable_region(generic_param_scope, lifetime) {
928 Some(info) if !lifetime.is_named(self.tcx) => {
929 (info.region_def_id.expect_local(), info.scope)
930 }
931 _ => return lifetime.get_name_or_anon(self.tcx).to_string(),
932 };
933
934 let new_lt = {
935 let generics = self.tcx.generics_of(lifetime_scope);
936 let mut used_names =
937 iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
938 .flat_map(|g| &g.own_params)
939 .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
940 .map(|p| p.name)
941 .collect::<Vec<_>>();
942 let hir_id = self.tcx.local_def_id_to_hir_id(lifetime_scope);
943 used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(
945 |p| match p {
946 ty::BoundVariableKind::Region(lt) => lt.get_name(self.tcx),
947 _ => None,
948 },
949 ));
950 (b'a'..=b'z')
951 .map(|c| format!("'{}", c as char))
952 .find(|candidate| !used_names.iter().any(|e| e.as_str() == candidate))
953 .unwrap_or_else(|| "'lt".to_string())
954 };
955
956 let mut visitor = LifetimeReplaceVisitor {
957 needle: hir::LifetimeKind::Param(lifetime_def_id),
958 add_lt_suggs,
959 new_lt: &new_lt,
960 };
961 match self.tcx.expect_hir_owner_node(lifetime_scope) {
962 hir::OwnerNode::Item(i) => visitor.visit_item(i),
963 hir::OwnerNode::ForeignItem(i) => visitor.visit_foreign_item(i),
964 hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i),
965 hir::OwnerNode::TraitItem(i) => visitor.visit_trait_item(i),
966 hir::OwnerNode::Crate(_) => bug!("OwnerNode::Crate doesn't not have generics"),
967 hir::OwnerNode::Synthetic => unreachable!(),
968 }
969
970 let ast_generics = self.tcx.hir_get_generics(lifetime_scope).unwrap();
971 let sugg = ast_generics
972 .span_for_lifetime_suggestion()
973 .map(|span| (span, format!("{new_lt}, ")))
974 .unwrap_or_else(|| (ast_generics.span, format!("<{new_lt}>")));
975 add_lt_suggs.push(sugg);
976
977 new_lt
978 }
979
980 fn report_sub_sup_conflict(
981 &self,
982 generic_param_scope: LocalDefId,
983 var_origin: RegionVariableOrigin,
984 sub_origin: SubregionOrigin<'tcx>,
985 sub_region: Region<'tcx>,
986 sup_origin: SubregionOrigin<'tcx>,
987 sup_region: Region<'tcx>,
988 ) -> ErrorGuaranteed {
989 let mut err = self.report_inference_failure(var_origin);
990
991 note_and_explain_region(
992 self.tcx,
993 &mut err,
994 generic_param_scope,
995 "first, the lifetime cannot outlive ",
996 sup_region,
997 "...",
998 None,
999 );
1000
1001 debug!("report_sub_sup_conflict: var_origin={:?}", var_origin);
1002 debug!("report_sub_sup_conflict: sub_region={:?}", sub_region);
1003 debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin);
1004 debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
1005 debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
1006
1007 if let SubregionOrigin::Subtype(ref sup_trace) = sup_origin
1008 && let SubregionOrigin::Subtype(ref sub_trace) = sub_origin
1009 && let Some((sup_expected, sup_found)) =
1010 self.values_str(sup_trace.values, &sup_trace.cause, err.long_ty_path())
1011 && let Some((sub_expected, sub_found)) =
1012 self.values_str(sub_trace.values, &sup_trace.cause, err.long_ty_path())
1013 && sub_expected == sup_expected
1014 && sub_found == sup_found
1015 {
1016 note_and_explain_region(
1017 self.tcx,
1018 &mut err,
1019 generic_param_scope,
1020 "...but the lifetime must also be valid for ",
1021 sub_region,
1022 "...",
1023 None,
1024 );
1025 err.span_note(
1026 sup_trace.cause.span,
1027 format!("...so that the {}", sup_trace.cause.as_requirement_str()),
1028 );
1029
1030 err.note_expected_found("", sup_expected, "", sup_found);
1031 return if sub_region.is_error() | sup_region.is_error() {
1032 err.delay_as_bug()
1033 } else {
1034 err.emit()
1035 };
1036 }
1037
1038 self.note_region_origin(&mut err, &sup_origin);
1039
1040 note_and_explain_region(
1041 self.tcx,
1042 &mut err,
1043 generic_param_scope,
1044 "but, the lifetime must be valid for ",
1045 sub_region,
1046 "...",
1047 None,
1048 );
1049
1050 self.note_region_origin(&mut err, &sub_origin);
1051 if sub_region.is_error() | sup_region.is_error() { err.delay_as_bug() } else { err.emit() }
1052 }
1053
1054 fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> {
1055 let br_string = |br: ty::BoundRegionKind| {
1056 let mut s = match br {
1057 ty::BoundRegionKind::Named(def_id) => self.tcx.item_name(def_id).to_string(),
1058 _ => String::new(),
1059 };
1060 if !s.is_empty() {
1061 s.push(' ');
1062 }
1063 s
1064 };
1065 let var_description = match var_origin {
1066 RegionVariableOrigin::Misc(_) => String::new(),
1067 RegionVariableOrigin::PatternRegion(_) => " for pattern".to_string(),
1068 RegionVariableOrigin::BorrowRegion(_) => " for borrow expression".to_string(),
1069 RegionVariableOrigin::Autoref(_) => " for autoref".to_string(),
1070 RegionVariableOrigin::Coercion(_) => " for automatic coercion".to_string(),
1071 RegionVariableOrigin::BoundRegion(_, br, BoundRegionConversionTime::FnCall) => {
1072 format!(" for lifetime parameter {}in function call", br_string(br))
1073 }
1074 RegionVariableOrigin::BoundRegion(
1075 _,
1076 br,
1077 BoundRegionConversionTime::HigherRankedType,
1078 ) => {
1079 format!(" for lifetime parameter {}in generic type", br_string(br))
1080 }
1081 RegionVariableOrigin::BoundRegion(
1082 _,
1083 br,
1084 BoundRegionConversionTime::AssocTypeProjection(def_id),
1085 ) => format!(
1086 " for lifetime parameter {}in trait containing associated type `{}`",
1087 br_string(br),
1088 self.tcx.associated_item(def_id).name()
1089 ),
1090 RegionVariableOrigin::RegionParameterDefinition(_, name) => {
1091 format!(" for lifetime parameter `{name}`")
1092 }
1093 RegionVariableOrigin::UpvarRegion(ref upvar_id, _) => {
1094 let var_name = self.tcx.hir_name(upvar_id.var_path.hir_id);
1095 format!(" for capture of `{var_name}` by closure")
1096 }
1097 RegionVariableOrigin::Nll(..) => bug!("NLL variable found in lexical phase"),
1098 };
1099
1100 struct_span_code_err!(
1101 self.dcx(),
1102 var_origin.span(),
1103 E0803,
1104 "cannot infer an appropriate lifetime{} due to conflicting requirements",
1105 var_description
1106 )
1107 }
1108}
1109
1110enum LifetimeSuggestion {
1111 NeedsPlus(Option<Span>),
1112 NeedsColon,
1113 HasColon,
1114}
1115
1116pub(super) fn note_and_explain_region<'tcx>(
1117 tcx: TyCtxt<'tcx>,
1118 err: &mut Diag<'_>,
1119 generic_param_scope: LocalDefId,
1120 prefix: &str,
1121 region: ty::Region<'tcx>,
1122 suffix: &str,
1123 alt_span: Option<Span>,
1124) {
1125 let (description, span) = match region.kind() {
1126 ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReStatic => {
1127 msg_span_from_named_region(tcx, generic_param_scope, region, alt_span)
1128 }
1129
1130 ty::ReError(_) => return,
1131
1132 ty::ReVar(_) => (format!("lifetime `{region}`"), alt_span),
1134
1135 ty::ReBound(..) | ty::ReErased => {
1136 bug!("unexpected region for note_and_explain_region: {:?}", region);
1137 }
1138 };
1139
1140 emit_msg_span(err, prefix, description, span, suffix);
1141}
1142
1143fn explain_free_region<'tcx>(
1144 tcx: TyCtxt<'tcx>,
1145 err: &mut Diag<'_>,
1146 generic_param_scope: LocalDefId,
1147 prefix: &str,
1148 region: ty::Region<'tcx>,
1149 suffix: &str,
1150) {
1151 let (description, span) = msg_span_from_named_region(tcx, generic_param_scope, region, None);
1152
1153 label_msg_span(err, prefix, description, span, suffix);
1154}
1155
1156fn msg_span_from_named_region<'tcx>(
1157 tcx: TyCtxt<'tcx>,
1158 generic_param_scope: LocalDefId,
1159 region: ty::Region<'tcx>,
1160 alt_span: Option<Span>,
1161) -> (String, Option<Span>) {
1162 match region.kind() {
1163 ty::ReEarlyParam(br) => {
1164 let param_def_id = tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id;
1165 let span = tcx.def_span(param_def_id);
1166 let text = if br.is_named() {
1167 format!("the lifetime `{}` as defined here", br.name)
1168 } else {
1169 "the anonymous lifetime as defined here".to_string()
1170 };
1171 (text, Some(span))
1172 }
1173 ty::ReLateParam(ref fr) => {
1174 if !fr.kind.is_named(tcx)
1175 && let Some((ty, _)) = find_anon_type(tcx, generic_param_scope, region)
1176 {
1177 ("the anonymous lifetime defined here".to_string(), Some(ty.span))
1178 } else {
1179 match fr.kind {
1180 ty::LateParamRegionKind::Named(param_def_id) => {
1181 let name = tcx.item_name(param_def_id);
1182 let span = tcx.def_span(param_def_id);
1183 let text = if name == kw::UnderscoreLifetime {
1184 "the anonymous lifetime as defined here".to_string()
1185 } else {
1186 format!("the lifetime `{name}` as defined here")
1187 };
1188 (text, Some(span))
1189 }
1190 ty::LateParamRegionKind::Anon(_) => (
1191 "the anonymous lifetime as defined here".to_string(),
1192 Some(tcx.def_span(generic_param_scope)),
1193 ),
1194 _ => (
1195 format!("the lifetime `{region}` as defined here"),
1196 Some(tcx.def_span(generic_param_scope)),
1197 ),
1198 }
1199 }
1200 }
1201 ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
1202 ty::RePlaceholder(ty::PlaceholderRegion {
1203 bound: ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id), .. },
1204 ..
1205 }) => (
1206 format!("the lifetime `{}` as defined here", tcx.item_name(def_id)),
1207 Some(tcx.def_span(def_id)),
1208 ),
1209 ty::RePlaceholder(ty::PlaceholderRegion {
1210 bound: ty::BoundRegion { kind: ty::BoundRegionKind::Anon, .. },
1211 ..
1212 }) => ("an anonymous lifetime".to_owned(), None),
1213 _ => bug!("{:?}", region),
1214 }
1215}
1216
1217fn emit_msg_span(
1218 err: &mut Diag<'_>,
1219 prefix: &str,
1220 description: String,
1221 span: Option<Span>,
1222 suffix: &str,
1223) {
1224 let message = format!("{prefix}{description}{suffix}");
1225
1226 if let Some(span) = span {
1227 err.span_note(span, message);
1228 } else {
1229 err.note(message);
1230 }
1231}
1232
1233fn label_msg_span(
1234 err: &mut Diag<'_>,
1235 prefix: &str,
1236 description: String,
1237 span: Option<Span>,
1238 suffix: &str,
1239) {
1240 let message = format!("{prefix}{description}{suffix}");
1241
1242 if let Some(span) = span {
1243 err.span_label(span, message);
1244 } else {
1245 err.note(message);
1246 }
1247}
1248
1249#[instrument(level = "trace", skip(infcx))]
1250pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
1251 infcx: &'a InferCtxt<'tcx>,
1252 generic_param_scope: LocalDefId,
1253 span: Span,
1254 hidden_ty: Ty<'tcx>,
1255 hidden_region: ty::Region<'tcx>,
1256 opaque_ty_key: ty::OpaqueTypeKey<'tcx>,
1257) -> Diag<'a> {
1258 let tcx = infcx.tcx;
1259 let mut err = infcx.dcx().create_err(errors::OpaqueCapturesLifetime {
1260 span,
1261 opaque_ty: Ty::new_opaque(tcx, opaque_ty_key.def_id.to_def_id(), opaque_ty_key.args),
1262 opaque_ty_span: tcx.def_span(opaque_ty_key.def_id),
1263 });
1264
1265 match hidden_region.kind() {
1267 ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
1268 explain_free_region(
1277 tcx,
1278 &mut err,
1279 generic_param_scope,
1280 &format!("hidden type `{hidden_ty}` captures "),
1281 hidden_region,
1282 "",
1283 );
1284 if let Some(_) = tcx.is_suitable_region(generic_param_scope, hidden_region) {
1285 suggest_precise_capturing(tcx, opaque_ty_key.def_id, hidden_region, &mut err);
1286 }
1287 }
1288 ty::RePlaceholder(_) => {
1289 explain_free_region(
1290 tcx,
1291 &mut err,
1292 generic_param_scope,
1293 &format!("hidden type `{}` captures ", hidden_ty),
1294 hidden_region,
1295 "",
1296 );
1297 }
1298 ty::ReError(_) => {
1299 err.downgrade_to_delayed_bug();
1300 }
1301 _ => {
1302 note_and_explain_region(
1318 tcx,
1319 &mut err,
1320 generic_param_scope,
1321 &format!("hidden type `{hidden_ty}` captures "),
1322 hidden_region,
1323 "",
1324 None,
1325 );
1326 }
1327 }
1328
1329 err
1330}
1331
1332fn suggest_precise_capturing<'tcx>(
1333 tcx: TyCtxt<'tcx>,
1334 opaque_def_id: LocalDefId,
1335 captured_lifetime: ty::Region<'tcx>,
1336 diag: &mut Diag<'_>,
1337) {
1338 let hir::OpaqueTy { bounds, origin, .. } =
1339 tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
1340
1341 let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } = *origin else {
1342 return;
1343 };
1344
1345 let new_lifetime = Symbol::intern(&captured_lifetime.to_string());
1346
1347 if let Some((args, span)) = bounds.iter().find_map(|bound| match bound {
1348 hir::GenericBound::Use(args, span) => Some((args, span)),
1349 _ => None,
1350 }) {
1351 let last_lifetime_span = args.iter().rev().find_map(|arg| match arg {
1352 hir::PreciseCapturingArg::Lifetime(lt) => Some(lt.ident.span),
1353 _ => None,
1354 });
1355
1356 let first_param_span = args.iter().find_map(|arg| match arg {
1357 hir::PreciseCapturingArg::Param(p) => Some(p.ident.span),
1358 _ => None,
1359 });
1360
1361 let (span, pre, post) = if let Some(last_lifetime_span) = last_lifetime_span {
1362 (last_lifetime_span.shrink_to_hi(), ", ", "")
1363 } else if let Some(first_param_span) = first_param_span {
1364 (first_param_span.shrink_to_lo(), "", ", ")
1365 } else {
1366 (span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), "", "")
1370 };
1371
1372 diag.subdiagnostic(errors::AddPreciseCapturing::Existing { span, new_lifetime, pre, post });
1373 } else {
1374 let mut captured_lifetimes = FxIndexSet::default();
1375 let mut captured_non_lifetimes = FxIndexSet::default();
1376
1377 let variances = tcx.variances_of(opaque_def_id);
1378 let mut generics = tcx.generics_of(opaque_def_id);
1379 let mut synthetics = vec![];
1380 loop {
1381 for param in &generics.own_params {
1382 if variances[param.index as usize] == ty::Bivariant {
1383 continue;
1384 }
1385
1386 match param.kind {
1387 ty::GenericParamDefKind::Lifetime => {
1388 captured_lifetimes.insert(param.name);
1389 }
1390 ty::GenericParamDefKind::Type { synthetic: true, .. } => {
1391 synthetics.push((tcx.def_span(param.def_id), param.name));
1392 }
1393 ty::GenericParamDefKind::Type { .. }
1394 | ty::GenericParamDefKind::Const { .. } => {
1395 captured_non_lifetimes.insert(param.name);
1396 }
1397 }
1398 }
1399
1400 if let Some(parent) = generics.parent {
1401 generics = tcx.generics_of(parent);
1402 } else {
1403 break;
1404 }
1405 }
1406
1407 if !captured_lifetimes.insert(new_lifetime) {
1408 return;
1410 }
1411
1412 if synthetics.is_empty() {
1413 let concatenated_bounds = captured_lifetimes
1414 .into_iter()
1415 .chain(captured_non_lifetimes)
1416 .map(|sym| sym.to_string())
1417 .collect::<Vec<_>>()
1418 .join(", ");
1419
1420 diag.subdiagnostic(errors::AddPreciseCapturing::New {
1421 span: tcx.def_span(opaque_def_id).shrink_to_hi(),
1422 new_lifetime,
1423 concatenated_bounds,
1424 });
1425 } else {
1426 let mut next_fresh_param = || {
1427 ["T", "U", "V", "W", "X", "Y", "A", "B", "C"]
1428 .into_iter()
1429 .map(Symbol::intern)
1430 .chain((0..).map(|i| Symbol::intern(&format!("T{i}"))))
1431 .find(|s| captured_non_lifetimes.insert(*s))
1432 .unwrap()
1433 };
1434
1435 let mut new_params = String::new();
1436 let mut suggs = vec![];
1437 let mut apit_spans = vec![];
1438
1439 for (i, (span, name)) in synthetics.into_iter().enumerate() {
1440 apit_spans.push(span);
1441
1442 let fresh_param = next_fresh_param();
1443
1444 suggs.push((span, fresh_param.to_string()));
1446
1447 if i > 0 {
1455 new_params += ", ";
1456 }
1457 let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start();
1458 new_params += fresh_param.as_str();
1459 new_params += ": ";
1460 new_params += name_as_bounds;
1461 }
1462
1463 let Some(generics) = tcx.hir_get_generics(fn_def_id) else {
1464 return;
1466 };
1467
1468 suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() {
1470 (params_span, format!(", {new_params}"))
1471 } else {
1472 (generics.span, format!("<{new_params}>"))
1473 });
1474
1475 let concatenated_bounds = captured_lifetimes
1476 .into_iter()
1477 .chain(captured_non_lifetimes)
1478 .map(|sym| sym.to_string())
1479 .collect::<Vec<_>>()
1480 .join(", ");
1481
1482 suggs.push((
1483 tcx.def_span(opaque_def_id).shrink_to_hi(),
1484 format!(" + use<{concatenated_bounds}>"),
1485 ));
1486
1487 diag.subdiagnostic(errors::AddPreciseCapturingAndParams {
1488 suggs,
1489 new_lifetime,
1490 apit_spans,
1491 });
1492 }
1493 }
1494}