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