]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Auto merge of #105145 - Ayush1325:sequential-remote-server, r=Mark-Simulacrum
[rust.git] / compiler / rustc_borrowck / src / diagnostics / region_errors.rs
1 #![deny(rustc::untranslatable_diagnostic)]
2 #![deny(rustc::diagnostic_outside_of_impl)]
3 //! Error reporting machinery for lifetime errors.
4
5 use rustc_data_structures::fx::FxIndexSet;
6 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
7 use rustc_hir::def_id::DefId;
8 use rustc_hir::intravisit::Visitor;
9 use rustc_hir::{self as hir, Item, ItemKind, Node};
10 use rustc_infer::infer::{
11     error_reporting::nice_region_error::{
12         self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
13         HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor,
14     },
15     error_reporting::unexpected_hidden_region_diagnostic,
16     NllRegionVariableOrigin, RelateParamBound,
17 };
18 use rustc_middle::hir::place::PlaceBase;
19 use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
20 use rustc_middle::ty::subst::InternalSubsts;
21 use rustc_middle::ty::Region;
22 use rustc_middle::ty::TypeVisitor;
23 use rustc_middle::ty::{self, RegionVid, Ty};
24 use rustc_span::symbol::{kw, Ident};
25 use rustc_span::Span;
26
27 use crate::borrowck_errors;
28 use crate::session_diagnostics::{
29     FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
30     LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
31 };
32
33 use super::{OutlivesSuggestionBuilder, RegionName};
34 use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
35 use crate::{
36     nll::ConstraintDescription,
37     region_infer::{values::RegionElement, TypeTest},
38     universal_regions::DefiningTy,
39     MirBorrowckCtxt,
40 };
41
42 impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
43     fn description(&self) -> &'static str {
44         // Must end with a space. Allows for empty names to be provided.
45         match self {
46             ConstraintCategory::Assignment => "assignment ",
47             ConstraintCategory::Return(_) => "returning this value ",
48             ConstraintCategory::Yield => "yielding this value ",
49             ConstraintCategory::UseAsConst => "using this value as a constant ",
50             ConstraintCategory::UseAsStatic => "using this value as a static ",
51             ConstraintCategory::Cast => "cast ",
52             ConstraintCategory::CallArgument(_) => "argument ",
53             ConstraintCategory::TypeAnnotation => "type annotation ",
54             ConstraintCategory::ClosureBounds => "closure body ",
55             ConstraintCategory::SizedBound => "proving this value is `Sized` ",
56             ConstraintCategory::CopyBound => "copying this value ",
57             ConstraintCategory::OpaqueType => "opaque type ",
58             ConstraintCategory::ClosureUpvar(_) => "closure capture ",
59             ConstraintCategory::Usage => "this usage ",
60             ConstraintCategory::Predicate(_)
61             | ConstraintCategory::Boring
62             | ConstraintCategory::BoringNoLocation
63             | ConstraintCategory::Internal => "",
64         }
65     }
66 }
67
68 /// A collection of errors encountered during region inference. This is needed to efficiently
69 /// report errors after borrow checking.
70 ///
71 /// Usually we expect this to either be empty or contain a small number of items, so we can avoid
72 /// allocation most of the time.
73 pub(crate) type RegionErrors<'tcx> = Vec<RegionErrorKind<'tcx>>;
74
75 #[derive(Clone, Debug)]
76 pub(crate) enum RegionErrorKind<'tcx> {
77     /// A generic bound failure for a type test (`T: 'a`).
78     TypeTestError { type_test: TypeTest<'tcx> },
79
80     /// An unexpected hidden region for an opaque type.
81     UnexpectedHiddenRegion {
82         /// The span for the member constraint.
83         span: Span,
84         /// The hidden type.
85         hidden_ty: Ty<'tcx>,
86         /// The opaque type.
87         key: ty::OpaqueTypeKey<'tcx>,
88         /// The unexpected region.
89         member_region: ty::Region<'tcx>,
90     },
91
92     /// Higher-ranked subtyping error.
93     BoundUniversalRegionError {
94         /// The placeholder free region.
95         longer_fr: RegionVid,
96         /// The region element that erroneously must be outlived by `longer_fr`.
97         error_element: RegionElement,
98         /// The placeholder region.
99         placeholder: ty::PlaceholderRegion,
100     },
101
102     /// Any other lifetime error.
103     RegionError {
104         /// The origin of the region.
105         fr_origin: NllRegionVariableOrigin,
106         /// The region that should outlive `shorter_fr`.
107         longer_fr: RegionVid,
108         /// The region that should be shorter, but we can't prove it.
109         shorter_fr: RegionVid,
110         /// Indicates whether this is a reported error. We currently only report the first error
111         /// encountered and leave the rest unreported so as not to overwhelm the user.
112         is_reported: bool,
113     },
114 }
115
116 /// Information about the various region constraints involved in a borrow checker error.
117 #[derive(Clone, Debug)]
118 pub struct ErrorConstraintInfo<'tcx> {
119     // fr: outlived_fr
120     pub(super) fr: RegionVid,
121     pub(super) fr_is_local: bool,
122     pub(super) outlived_fr: RegionVid,
123     pub(super) outlived_fr_is_local: bool,
124
125     // Category and span for best blame constraint
126     pub(super) category: ConstraintCategory<'tcx>,
127     pub(super) span: Span,
128 }
129
130 impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
131     /// Converts a region inference variable into a `ty::Region` that
132     /// we can use for error reporting. If `r` is universally bound,
133     /// then we use the name that we have on record for it. If `r` is
134     /// existentially bound, then we check its inferred value and try
135     /// to find a good name from that. Returns `None` if we can't find
136     /// one (e.g., this is just some random part of the CFG).
137     pub(super) fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
138         self.to_error_region_vid(r).and_then(|r| self.regioncx.region_definition(r).external_name)
139     }
140
141     /// Returns the `RegionVid` corresponding to the region returned by
142     /// `to_error_region`.
143     pub(super) fn to_error_region_vid(&self, r: RegionVid) -> Option<RegionVid> {
144         if self.regioncx.universal_regions().is_universal_region(r) {
145             Some(r)
146         } else {
147             // We just want something nameable, even if it's not
148             // actually an upper bound.
149             let upper_bound = self.regioncx.approx_universal_upper_bound(r);
150
151             if self.regioncx.upper_bound_in_region_scc(r, upper_bound) {
152                 self.to_error_region_vid(upper_bound)
153             } else {
154                 None
155             }
156         }
157     }
158
159     /// Returns `true` if a closure is inferred to be an `FnMut` closure.
160     fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
161         if let Some(ty::ReFree(free_region)) = self.to_error_region(fr).as_deref()
162             && let ty::BoundRegionKind::BrEnv = free_region.bound_region
163             && let DefiningTy::Closure(_, substs) = self.regioncx.universal_regions().defining_ty
164         {
165             return substs.as_closure().kind() == ty::ClosureKind::FnMut;
166         }
167
168         false
169     }
170
171     /// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`.
172     pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
173         // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are
174         // buffered in the `MirBorrowckCtxt`.
175
176         let mut outlives_suggestion = OutlivesSuggestionBuilder::default();
177
178         for nll_error in nll_errors.into_iter() {
179             match nll_error {
180                 RegionErrorKind::TypeTestError { type_test } => {
181                     // Try to convert the lower-bound region into something named we can print for the user.
182                     let lower_bound_region = self.to_error_region(type_test.lower_bound);
183
184                     let type_test_span = type_test.span;
185
186                     if let Some(lower_bound_region) = lower_bound_region {
187                         let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx);
188                         let origin = RelateParamBound(type_test_span, generic_ty, None);
189                         self.buffer_error(self.infcx.err_ctxt().construct_generic_bound_failure(
190                             self.body.source.def_id().expect_local(),
191                             type_test_span,
192                             Some(origin),
193                             type_test.generic_kind,
194                             lower_bound_region,
195                         ));
196                     } else {
197                         // FIXME. We should handle this case better. It
198                         // indicates that we have e.g., some region variable
199                         // whose value is like `'a+'b` where `'a` and `'b` are
200                         // distinct unrelated universal regions that are not
201                         // known to outlive one another. It'd be nice to have
202                         // some examples where this arises to decide how best
203                         // to report it; we could probably handle it by
204                         // iterating over the universal regions and reporting
205                         // an error that multiple bounds are required.
206                         self.buffer_error(self.infcx.tcx.sess.create_err(
207                             GenericDoesNotLiveLongEnough {
208                                 kind: type_test.generic_kind.to_string(),
209                                 span: type_test_span,
210                             },
211                         ));
212                     }
213                 }
214
215                 RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, key, member_region } => {
216                     let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
217                     let named_key = self.regioncx.name_regions(self.infcx.tcx, key);
218                     let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
219                     self.buffer_error(unexpected_hidden_region_diagnostic(
220                         self.infcx.tcx,
221                         span,
222                         named_ty,
223                         named_region,
224                         named_key,
225                     ));
226                 }
227
228                 RegionErrorKind::BoundUniversalRegionError {
229                     longer_fr,
230                     placeholder,
231                     error_element,
232                 } => {
233                     let error_vid = self.regioncx.region_from_element(longer_fr, &error_element);
234
235                     // Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
236                     let (_, cause) = self.regioncx.find_outlives_blame_span(
237                         longer_fr,
238                         NllRegionVariableOrigin::Placeholder(placeholder),
239                         error_vid,
240                     );
241
242                     let universe = placeholder.universe;
243                     let universe_info = self.regioncx.universe_info(universe);
244
245                     universe_info.report_error(self, placeholder, error_element, cause);
246                 }
247
248                 RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
249                     if is_reported {
250                         self.report_region_error(
251                             longer_fr,
252                             fr_origin,
253                             shorter_fr,
254                             &mut outlives_suggestion,
255                         );
256                     } else {
257                         // We only report the first error, so as not to overwhelm the user. See
258                         // `RegRegionErrorKind` docs.
259                         //
260                         // FIXME: currently we do nothing with these, but perhaps we can do better?
261                         // FIXME: try collecting these constraints on the outlives suggestion
262                         // builder. Does it make the suggestions any better?
263                         debug!(
264                             "Unreported region error: can't prove that {:?}: {:?}",
265                             longer_fr, shorter_fr
266                         );
267                     }
268                 }
269             }
270         }
271
272         // Emit one outlives suggestions for each MIR def we borrowck
273         outlives_suggestion.add_suggestion(self);
274     }
275
276     fn get_impl_ident_and_self_ty_from_trait(
277         &self,
278         def_id: DefId,
279         trait_objects: &FxIndexSet<DefId>,
280     ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
281         let tcx = self.infcx.tcx;
282         match tcx.hir().get_if_local(def_id) {
283             Some(Node::ImplItem(impl_item)) => {
284                 match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
285                 {
286                     Some(Node::Item(Item {
287                         kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
288                         ..
289                     })) => Some((impl_item.ident, self_ty)),
290                     _ => None,
291                 }
292             }
293             Some(Node::TraitItem(trait_item)) => {
294                 let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
295                 match tcx.hir().find_by_def_id(trait_did.def_id) {
296                     Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
297                         // The method being called is defined in the `trait`, but the `'static`
298                         // obligation comes from the `impl`. Find that `impl` so that we can point
299                         // at it in the suggestion.
300                         let trait_did = trait_did.to_def_id();
301                         match tcx
302                             .hir()
303                             .trait_impls(trait_did)
304                             .iter()
305                             .filter_map(|&impl_did| {
306                                 match tcx.hir().get_if_local(impl_did.to_def_id()) {
307                                     Some(Node::Item(Item {
308                                         kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
309                                         ..
310                                     })) if trait_objects.iter().all(|did| {
311                                         // FIXME: we should check `self_ty` against the receiver
312                                         // type in the `UnifyReceiver` context, but for now, use
313                                         // this imperfect proxy. This will fail if there are
314                                         // multiple `impl`s for the same trait like
315                                         // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
316                                         // In that case, only the first one will get suggestions.
317                                         let mut traits = vec![];
318                                         let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
319                                         hir_v.visit_ty(self_ty);
320                                         !traits.is_empty()
321                                     }) =>
322                                     {
323                                         Some(self_ty)
324                                     }
325                                     _ => None,
326                                 }
327                             })
328                             .next()
329                         {
330                             Some(self_ty) => Some((trait_item.ident, self_ty)),
331                             _ => None,
332                         }
333                     }
334                     _ => None,
335                 }
336             }
337             _ => None,
338         }
339     }
340
341     /// Report an error because the universal region `fr` was required to outlive
342     /// `outlived_fr` but it is not known to do so. For example:
343     ///
344     /// ```compile_fail
345     /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
346     /// ```
347     ///
348     /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
349     pub(crate) fn report_region_error(
350         &mut self,
351         fr: RegionVid,
352         fr_origin: NllRegionVariableOrigin,
353         outlived_fr: RegionVid,
354         outlives_suggestion: &mut OutlivesSuggestionBuilder,
355     ) {
356         debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
357
358         let (blame_constraint, extra_info) =
359             self.regioncx.best_blame_constraint(fr, fr_origin, |r| {
360                 self.regioncx.provides_universal_region(r, fr, outlived_fr)
361             });
362         let BlameConstraint { category, cause, variance_info, .. } = blame_constraint;
363
364         debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
365
366         // Check if we can use one of the "nice region errors".
367         if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
368             let infer_err = self.infcx.err_ctxt();
369             let nice = NiceRegionError::new_from_span(&infer_err, cause.span, o, f);
370             if let Some(diag) = nice.try_report_from_nll() {
371                 self.buffer_error(diag);
372                 return;
373             }
374         }
375
376         let (fr_is_local, outlived_fr_is_local): (bool, bool) = (
377             self.regioncx.universal_regions().is_local_free_region(fr),
378             self.regioncx.universal_regions().is_local_free_region(outlived_fr),
379         );
380
381         debug!(
382             "report_region_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
383             fr_is_local, outlived_fr_is_local, category
384         );
385
386         let errci = ErrorConstraintInfo {
387             fr,
388             outlived_fr,
389             fr_is_local,
390             outlived_fr_is_local,
391             category,
392             span: cause.span,
393         };
394
395         let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
396             (ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => {
397                 self.report_fnmut_error(&errci, kind)
398             }
399             (ConstraintCategory::Assignment, true, false)
400             | (ConstraintCategory::CallArgument(_), true, false) => {
401                 let mut db = self.report_escaping_data_error(&errci);
402
403                 outlives_suggestion.intermediate_suggestion(self, &errci, &mut db);
404                 outlives_suggestion.collect_constraint(fr, outlived_fr);
405
406                 db
407             }
408             _ => {
409                 let mut db = self.report_general_error(&errci);
410
411                 outlives_suggestion.intermediate_suggestion(self, &errci, &mut db);
412                 outlives_suggestion.collect_constraint(fr, outlived_fr);
413
414                 db
415             }
416         };
417
418         match variance_info {
419             ty::VarianceDiagInfo::None => {}
420             ty::VarianceDiagInfo::Invariant { ty, param_index } => {
421                 let (desc, note) = match ty.kind() {
422                     ty::RawPtr(ty_mut) => {
423                         assert_eq!(ty_mut.mutbl, rustc_hir::Mutability::Mut);
424                         (
425                             format!("a mutable pointer to `{}`", ty_mut.ty),
426                             "mutable pointers are invariant over their type parameter".to_string(),
427                         )
428                     }
429                     ty::Ref(_, inner_ty, mutbl) => {
430                         assert_eq!(*mutbl, rustc_hir::Mutability::Mut);
431                         (
432                             format!("a mutable reference to `{inner_ty}`"),
433                             "mutable references are invariant over their type parameter"
434                                 .to_string(),
435                         )
436                     }
437                     ty::Adt(adt, substs) => {
438                         let generic_arg = substs[param_index as usize];
439                         let identity_substs =
440                             InternalSubsts::identity_for_item(self.infcx.tcx, adt.did());
441                         let base_ty = self.infcx.tcx.mk_adt(*adt, identity_substs);
442                         let base_generic_arg = identity_substs[param_index as usize];
443                         let adt_desc = adt.descr();
444
445                         let desc = format!(
446                             "the type `{ty}`, which makes the generic argument `{generic_arg}` invariant"
447                         );
448                         let note = format!(
449                             "the {adt_desc} `{base_ty}` is invariant over the parameter `{base_generic_arg}`"
450                         );
451                         (desc, note)
452                     }
453                     ty::FnDef(def_id, _) => {
454                         let name = self.infcx.tcx.item_name(*def_id);
455                         let identity_substs =
456                             InternalSubsts::identity_for_item(self.infcx.tcx, *def_id);
457                         let desc = format!("a function pointer to `{name}`");
458                         let note = format!(
459                             "the function `{name}` is invariant over the parameter `{}`",
460                             identity_substs[param_index as usize]
461                         );
462                         (desc, note)
463                     }
464                     _ => panic!("Unexpected type {:?}", ty),
465                 };
466                 diag.note(&format!("requirement occurs because of {desc}",));
467                 diag.note(&note);
468                 diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance");
469             }
470         }
471
472         for extra in extra_info {
473             match extra {
474                 ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
475                     diag.span_note(span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
476                 }
477             }
478         }
479
480         self.buffer_error(diag);
481     }
482
483     /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
484     /// This function expects `fr` to be local and `outlived_fr` to not be local.
485     ///
486     /// ```text
487     /// error: captured variable cannot escape `FnMut` closure body
488     ///   --> $DIR/issue-53040.rs:15:8
489     ///    |
490     /// LL |     || &mut v;
491     ///    |     -- ^^^^^^ creates a reference to a captured variable which escapes the closure body
492     ///    |     |
493     ///    |     inferred to be a `FnMut` closure
494     ///    |
495     ///    = note: `FnMut` closures only have access to their captured variables while they are
496     ///            executing...
497     ///    = note: ...therefore, returned references to captured variables will escape the closure
498     /// ```
499     fn report_fnmut_error(
500         &self,
501         errci: &ErrorConstraintInfo<'tcx>,
502         kind: ReturnConstraint,
503     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
504         let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
505
506         let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
507         if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *output_ty.kind() {
508             output_ty = self.infcx.tcx.type_of(def_id)
509         };
510
511         debug!("report_fnmut_error: output_ty={:?}", output_ty);
512
513         let err = FnMutError {
514             span: *span,
515             ty_err: match output_ty.kind() {
516                 ty::Closure(_, _) => FnMutReturnTypeErr::ReturnClosure { span: *span },
517                 ty::Generator(def, ..) if self.infcx.tcx.generator_is_async(*def) => {
518                     FnMutReturnTypeErr::ReturnAsyncBlock { span: *span }
519                 }
520                 _ => FnMutReturnTypeErr::ReturnRef { span: *span },
521             },
522         };
523
524         let mut diag = self.infcx.tcx.sess.create_err(err);
525
526         if let ReturnConstraint::ClosureUpvar(upvar_field) = kind {
527             let def_id = match self.regioncx.universal_regions().defining_ty {
528                 DefiningTy::Closure(def_id, _) => def_id,
529                 ty => bug!("unexpected DefiningTy {:?}", ty),
530             };
531
532             let captured_place = &self.upvars[upvar_field.index()].place;
533             let defined_hir = match captured_place.place.base {
534                 PlaceBase::Local(hirid) => Some(hirid),
535                 PlaceBase::Upvar(upvar) => Some(upvar.var_path.hir_id),
536                 _ => None,
537             };
538
539             if let Some(def_hir) = defined_hir {
540                 let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap();
541                 let upvar_def_span = self.infcx.tcx.hir().span(def_hir);
542                 let upvar_span = upvars_map.get(&def_hir).unwrap().span;
543                 diag.subdiagnostic(VarHereDenote::Defined { span: upvar_def_span });
544                 diag.subdiagnostic(VarHereDenote::Captured { span: upvar_span });
545             }
546         }
547
548         if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
549             diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span });
550         }
551
552         self.suggest_move_on_borrowing_closure(&mut diag);
553
554         diag
555     }
556
557     /// Reports an error specifically for when data is escaping a closure.
558     ///
559     /// ```text
560     /// error: borrowed data escapes outside of function
561     ///   --> $DIR/lifetime-bound-will-change-warning.rs:44:5
562     ///    |
563     /// LL | fn test2<'a>(x: &'a Box<Fn()+'a>) {
564     ///    |              - `x` is a reference that is only valid in the function body
565     /// LL |     // but ref_obj will not, so warn.
566     /// LL |     ref_obj(x)
567     ///    |     ^^^^^^^^^^ `x` escapes the function body here
568     /// ```
569     #[instrument(level = "debug", skip(self))]
570     fn report_escaping_data_error(
571         &self,
572         errci: &ErrorConstraintInfo<'tcx>,
573     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
574         let ErrorConstraintInfo { span, category, .. } = errci;
575
576         let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
577             self.infcx.tcx,
578             &self.body,
579             &self.local_names,
580             &self.upvars,
581             errci.fr,
582         );
583         let outlived_fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
584             self.infcx.tcx,
585             &self.body,
586             &self.local_names,
587             &self.upvars,
588             errci.outlived_fr,
589         );
590
591         let (_, escapes_from) = self
592             .infcx
593             .tcx
594             .article_and_description(self.regioncx.universal_regions().defining_ty.def_id());
595
596         // Revert to the normal error in these cases.
597         // Assignments aren't "escapes" in function items.
598         if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none())
599             || (*category == ConstraintCategory::Assignment
600                 && self.regioncx.universal_regions().defining_ty.is_fn_def())
601             || self.regioncx.universal_regions().defining_ty.is_const()
602         {
603             return self.report_general_error(&ErrorConstraintInfo {
604                 fr_is_local: true,
605                 outlived_fr_is_local: false,
606                 ..*errci
607             });
608         }
609
610         let mut diag =
611             borrowck_errors::borrowed_data_escapes_closure(self.infcx.tcx, *span, escapes_from);
612
613         if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
614             diag.span_label(
615                 outlived_fr_span,
616                 format!("`{outlived_fr_name}` declared here, outside of the {escapes_from} body",),
617             );
618         }
619
620         if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
621             diag.span_label(
622                 fr_span,
623                 format!(
624                     "`{fr_name}` is a reference that is only valid in the {escapes_from} body",
625                 ),
626             );
627
628             diag.span_label(*span, format!("`{fr_name}` escapes the {escapes_from} body here"));
629         }
630
631         // Only show an extra note if we can find an 'error region' for both of the region
632         // variables. This avoids showing a noisy note that just mentions 'synthetic' regions
633         // that don't help the user understand the error.
634         match (self.to_error_region(errci.fr), self.to_error_region(errci.outlived_fr)) {
635             (Some(f), Some(o)) => {
636                 self.maybe_suggest_constrain_dyn_trait_impl(&mut diag, f, o, category);
637
638                 let fr_region_name = self.give_region_a_name(errci.fr).unwrap();
639                 fr_region_name.highlight_region_name(&mut diag);
640                 let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
641                 outlived_fr_region_name.highlight_region_name(&mut diag);
642
643                 diag.span_label(
644                     *span,
645                     format!(
646                         "{}requires that `{}` must outlive `{}`",
647                         category.description(),
648                         fr_region_name,
649                         outlived_fr_region_name,
650                     ),
651                 );
652             }
653             _ => {}
654         }
655
656         diag
657     }
658
659     /// Reports a region inference error for the general case with named/synthesized lifetimes to
660     /// explain what is happening.
661     ///
662     /// ```text
663     /// error: unsatisfied lifetime constraints
664     ///   --> $DIR/regions-creating-enums3.rs:17:5
665     ///    |
666     /// LL | fn mk_add_bad1<'a,'b>(x: &'a ast<'a>, y: &'b ast<'b>) -> ast<'a> {
667     ///    |                -- -- lifetime `'b` defined here
668     ///    |                |
669     ///    |                lifetime `'a` defined here
670     /// LL |     ast::add(x, y)
671     ///    |     ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
672     ///    |                    is returning data with lifetime `'b`
673     /// ```
674     fn report_general_error(
675         &self,
676         errci: &ErrorConstraintInfo<'tcx>,
677     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
678         let ErrorConstraintInfo {
679             fr,
680             fr_is_local,
681             outlived_fr,
682             outlived_fr_is_local,
683             span,
684             category,
685             ..
686         } = errci;
687
688         let (_, mir_def_name) =
689             self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id());
690
691         let err = LifetimeOutliveErr { span: *span };
692         let mut diag = self.infcx.tcx.sess.create_err(err);
693
694         let fr_name = self.give_region_a_name(*fr).unwrap();
695         fr_name.highlight_region_name(&mut diag);
696         let outlived_fr_name = self.give_region_a_name(*outlived_fr).unwrap();
697         outlived_fr_name.highlight_region_name(&mut diag);
698
699         let err_category = match (category, outlived_fr_is_local, fr_is_local) {
700             (ConstraintCategory::Return(_), true, _) => LifetimeReturnCategoryErr::WrongReturn {
701                 span: *span,
702                 mir_def_name,
703                 outlived_fr_name,
704                 fr_name: &fr_name,
705             },
706             _ => LifetimeReturnCategoryErr::ShortReturn {
707                 span: *span,
708                 category_desc: category.description(),
709                 free_region_name: &fr_name,
710                 outlived_fr_name,
711             },
712         };
713
714         diag.subdiagnostic(err_category);
715
716         self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
717         self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
718         self.suggest_move_on_borrowing_closure(&mut diag);
719
720         diag
721     }
722
723     /// Adds a suggestion to errors where an `impl Trait` is returned.
724     ///
725     /// ```text
726     /// help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as
727     ///       a constraint
728     ///    |
729     /// LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
730     ///    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
731     /// ```
732     fn add_static_impl_trait_suggestion(
733         &self,
734         diag: &mut Diagnostic,
735         fr: RegionVid,
736         // We need to pass `fr_name` - computing it again will label it twice.
737         fr_name: RegionName,
738         outlived_fr: RegionVid,
739     ) {
740         if let (Some(f), Some(outlived_f)) =
741             (self.to_error_region(fr), self.to_error_region(outlived_fr))
742         {
743             if *outlived_f != ty::ReStatic {
744                 return;
745             }
746
747             let fn_returns = self
748                 .infcx
749                 .tcx
750                 .is_suitable_region(f)
751                 .map(|r| self.infcx.tcx.return_type_impl_or_dyn_traits(r.def_id))
752                 .unwrap_or_default();
753
754             if fn_returns.is_empty() {
755                 return;
756             }
757
758             let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) {
759                 param
760             } else {
761                 return;
762             };
763
764             let lifetime = if f.has_name() { fr_name.name } else { kw::UnderscoreLifetime };
765
766             let arg = match param.param.pat.simple_ident() {
767                 Some(simple_ident) => format!("argument `{}`", simple_ident),
768                 None => "the argument".to_string(),
769             };
770             let captures = format!("captures data from {}", arg);
771
772             return nice_region_error::suggest_new_region_bound(
773                 self.infcx.tcx,
774                 diag,
775                 fn_returns,
776                 lifetime.to_string(),
777                 Some(arg),
778                 captures,
779                 Some((param.param_ty_span, param.param_ty.to_string())),
780             );
781         }
782     }
783
784     fn maybe_suggest_constrain_dyn_trait_impl(
785         &self,
786         diag: &mut Diagnostic,
787         f: Region<'tcx>,
788         o: Region<'tcx>,
789         category: &ConstraintCategory<'tcx>,
790     ) {
791         if !o.is_static() {
792             return;
793         }
794
795         let tcx = self.infcx.tcx;
796
797         let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category {
798             let (fn_did, substs) = match func_ty.kind() {
799                 ty::FnDef(fn_did, substs) => (fn_did, substs),
800                 _ => return,
801             };
802             debug!(?fn_did, ?substs);
803
804             // Only suggest this on function calls, not closures
805             let ty = tcx.type_of(fn_did);
806             debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind());
807             if let ty::Closure(_, _) = ty.kind() {
808                 return;
809             }
810
811             if let Ok(Some(instance)) = ty::Instance::resolve(
812                 tcx,
813                 self.param_env,
814                 *fn_did,
815                 self.infcx.resolve_vars_if_possible(substs),
816             ) {
817                 instance
818             } else {
819                 return;
820             }
821         } else {
822             return;
823         };
824
825         let param = match find_param_with_region(tcx, f, o) {
826             Some(param) => param,
827             None => return,
828         };
829         debug!(?param);
830
831         let mut visitor = TraitObjectVisitor(FxIndexSet::default());
832         visitor.visit_ty(param.param_ty);
833
834         let Some((ident, self_ty)) =
835             self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &visitor.0) else {return};
836
837         self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
838     }
839
840     #[instrument(skip(self, err), level = "debug")]
841     fn suggest_constrain_dyn_trait_in_impl(
842         &self,
843         err: &mut Diagnostic,
844         found_dids: &FxIndexSet<DefId>,
845         ident: Ident,
846         self_ty: &hir::Ty<'_>,
847     ) -> bool {
848         debug!("err: {:#?}", err);
849         let mut suggested = false;
850         for found_did in found_dids {
851             let mut traits = vec![];
852             let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
853             hir_v.visit_ty(&self_ty);
854             debug!("trait spans found: {:?}", traits);
855             for span in &traits {
856                 let mut multi_span: MultiSpan = vec![*span].into();
857                 multi_span
858                     .push_span_label(*span, "this has an implicit `'static` lifetime requirement");
859                 multi_span.push_span_label(
860                     ident.span,
861                     "calling this method introduces the `impl`'s 'static` requirement",
862                 );
863                 err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
864                 err.span_suggestion_verbose(
865                     span.shrink_to_hi(),
866                     "consider relaxing the implicit `'static` requirement",
867                     " + '_",
868                     Applicability::MaybeIncorrect,
869                 );
870                 suggested = true;
871             }
872         }
873         suggested
874     }
875
876     fn suggest_adding_lifetime_params(
877         &self,
878         diag: &mut Diagnostic,
879         sub: RegionVid,
880         sup: RegionVid,
881     ) {
882         let (Some(sub), Some(sup)) = (self.to_error_region(sub), self.to_error_region(sup)) else {
883             return
884         };
885
886         let Some((ty_sub, _)) = self
887             .infcx
888             .tcx
889             .is_suitable_region(sub)
890             .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sub, &anon_reg.boundregion)) else {
891             return
892         };
893
894         let Some((ty_sup, _)) = self
895             .infcx
896             .tcx
897             .is_suitable_region(sup)
898             .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sup, &anon_reg.boundregion)) else {
899             return
900         };
901
902         suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
903     }
904
905     fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
906         let map = self.infcx.tcx.hir();
907         let body_id = map.body_owned_by(self.mir_def_id());
908         let expr = &map.body(body_id).value;
909         let mut closure_span = None::<rustc_span::Span>;
910         match expr.kind {
911             hir::ExprKind::MethodCall(.., args, _) => {
912                 for arg in args {
913                     if let hir::ExprKind::Closure(hir::Closure {
914                         capture_clause: hir::CaptureBy::Ref,
915                         ..
916                     }) = arg.kind
917                     {
918                         closure_span = Some(arg.span.shrink_to_lo());
919                         break;
920                     }
921                 }
922             }
923             hir::ExprKind::Block(blk, _) => {
924                 if let Some(expr) = blk.expr {
925                     // only when the block is a closure
926                     if let hir::ExprKind::Closure(hir::Closure {
927                         capture_clause: hir::CaptureBy::Ref,
928                         body,
929                         ..
930                     }) = expr.kind
931                     {
932                         let body = map.body(*body);
933                         if !matches!(body.generator_kind, Some(hir::GeneratorKind::Async(..))) {
934                             closure_span = Some(expr.span.shrink_to_lo());
935                         }
936                     }
937                 }
938             }
939             _ => {}
940         }
941         if let Some(closure_span) = closure_span {
942             diag.span_suggestion_verbose(
943                 closure_span,
944                 "consider adding 'move' keyword before the nested closure",
945                 "move ",
946                 Applicability::MaybeIncorrect,
947             );
948         }
949     }
950 }