rustc_trait_selection/error_reporting/infer/
region.rs

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