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