]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_borrowck/src/diagnostics/region_errors.rs
New upstream version 1.62.1+dfsg1
[rustc.git] / compiler / rustc_borrowck / src / diagnostics / region_errors.rs
CommitLineData
60c5eb7d
XL
1//! Error reporting machinery for lifetime errors.
2
04454e1e 3use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
74b04a01 4use rustc_infer::infer::{
04454e1e
FG
5 error_reporting::nice_region_error::{
6 self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
7 NiceRegionError,
8 },
9 error_reporting::unexpected_hidden_region_diagnostic,
10 NllRegionVariableOrigin, RelateParamBound,
74b04a01 11};
5099ac24 12use rustc_middle::hir::place::PlaceBase;
f035d41b 13use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
04454e1e 14use rustc_middle::ty::subst::InternalSubsts;
ba9703b0 15use rustc_middle::ty::{self, RegionVid, Ty};
04454e1e
FG
16use rustc_span::symbol::sym;
17use rustc_span::Span;
60c5eb7d 18
c295e0f8 19use crate::borrowck_errors;
8faf50e0 20
c295e0f8
XL
21use super::{OutlivesSuggestionBuilder, RegionName};
22use crate::region_infer::BlameConstraint;
23use crate::{
60c5eb7d 24 nll::ConstraintDescription,
dfeec247
XL
25 region_infer::{values::RegionElement, TypeTest},
26 universal_regions::DefiningTy,
27 MirBorrowckCtxt,
60c5eb7d 28};
8faf50e0 29
0bf4aa26
XL
30impl ConstraintDescription for ConstraintCategory {
31 fn description(&self) -> &'static str {
8faf50e0
XL
32 // Must end with a space. Allows for empty names to be provided.
33 match self {
0bf4aa26 34 ConstraintCategory::Assignment => "assignment ",
f035d41b 35 ConstraintCategory::Return(_) => "returning this value ",
0731742a 36 ConstraintCategory::Yield => "yielding this value ",
0bf4aa26
XL
37 ConstraintCategory::UseAsConst => "using this value as a constant ",
38 ConstraintCategory::UseAsStatic => "using this value as a static ",
39 ConstraintCategory::Cast => "cast ",
40 ConstraintCategory::CallArgument => "argument ",
41 ConstraintCategory::TypeAnnotation => "type annotation ",
42 ConstraintCategory::ClosureBounds => "closure body ",
43 ConstraintCategory::SizedBound => "proving this value is `Sized` ",
44 ConstraintCategory::CopyBound => "copying this value ",
45 ConstraintCategory::OpaqueType => "opaque type ",
f035d41b 46 ConstraintCategory::ClosureUpvar(_) => "closure capture ",
c295e0f8
XL
47 ConstraintCategory::Usage => "this usage ",
48 ConstraintCategory::Predicate(_)
49 | ConstraintCategory::Boring
0bf4aa26
XL
50 | ConstraintCategory::BoringNoLocation
51 | ConstraintCategory::Internal => "",
8faf50e0
XL
52 }
53 }
54}
55
dfeec247
XL
56/// A collection of errors encountered during region inference. This is needed to efficiently
57/// report errors after borrow checking.
58///
59/// Usually we expect this to either be empty or contain a small number of items, so we can avoid
60/// allocation most of the time.
61crate type RegionErrors<'tcx> = Vec<RegionErrorKind<'tcx>>;
60c5eb7d 62
dfeec247
XL
63#[derive(Clone, Debug)]
64crate enum RegionErrorKind<'tcx> {
65 /// A generic bound failure for a type test (`T: 'a`).
66 TypeTestError { type_test: TypeTest<'tcx> },
67
68 /// An unexpected hidden region for an opaque type.
69 UnexpectedHiddenRegion {
74b04a01
XL
70 /// The span for the member constraint.
71 span: Span,
dfeec247
XL
72 /// The hidden type.
73 hidden_ty: Ty<'tcx>,
74 /// The unexpected region.
75 member_region: ty::Region<'tcx>,
76 },
77
78 /// Higher-ranked subtyping error.
79 BoundUniversalRegionError {
80 /// The placeholder free region.
81 longer_fr: RegionVid,
82 /// The region element that erroneously must be outlived by `longer_fr`.
83 error_element: RegionElement,
94222f64
XL
84 /// The placeholder region.
85 placeholder: ty::PlaceholderRegion,
dfeec247 86 },
e1599b0c 87
dfeec247
XL
88 /// Any other lifetime error.
89 RegionError {
90 /// The origin of the region.
5869c6ff 91 fr_origin: NllRegionVariableOrigin,
dfeec247
XL
92 /// The region that should outlive `shorter_fr`.
93 longer_fr: RegionVid,
94 /// The region that should be shorter, but we can't prove it.
95 shorter_fr: RegionVid,
96 /// Indicates whether this is a reported error. We currently only report the first error
97 /// encountered and leave the rest unreported so as not to overwhelm the user.
98 is_reported: bool,
99 },
e1599b0c
XL
100}
101
102/// Information about the various region constraints involved in a borrow checker error.
103#[derive(Clone, Debug)]
104pub struct ErrorConstraintInfo {
105 // fr: outlived_fr
60c5eb7d
XL
106 pub(super) fr: RegionVid,
107 pub(super) fr_is_local: bool,
108 pub(super) outlived_fr: RegionVid,
109 pub(super) outlived_fr_is_local: bool,
e1599b0c
XL
110
111 // Category and span for best blame constraint
60c5eb7d
XL
112 pub(super) category: ConstraintCategory,
113 pub(super) span: Span,
e1599b0c
XL
114}
115
dfeec247
XL
116impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
117 /// Converts a region inference variable into a `ty::Region` that
118 /// we can use for error reporting. If `r` is universally bound,
119 /// then we use the name that we have on record for it. If `r` is
120 /// existentially bound, then we check its inferred value and try
121 /// to find a good name from that. Returns `None` if we can't find
122 /// one (e.g., this is just some random part of the CFG).
123 pub(super) fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
124 self.to_error_region_vid(r).and_then(|r| self.regioncx.region_definition(r).external_name)
125 }
8faf50e0 126
dfeec247
XL
127 /// Returns the `RegionVid` corresponding to the region returned by
128 /// `to_error_region`.
129 pub(super) fn to_error_region_vid(&self, r: RegionVid) -> Option<RegionVid> {
130 if self.regioncx.universal_regions().is_universal_region(r) {
131 Some(r)
132 } else {
f035d41b
XL
133 // We just want something nameable, even if it's not
134 // actually an upper bound.
135 let upper_bound = self.regioncx.approx_universal_upper_bound(r);
8faf50e0 136
dfeec247
XL
137 if self.regioncx.upper_bound_in_region_scc(r, upper_bound) {
138 self.to_error_region_vid(upper_bound)
e74abb32 139 } else {
dfeec247 140 None
8faf50e0 141 }
dfeec247
XL
142 }
143 }
e74abb32 144
dfeec247
XL
145 /// Returns `true` if a closure is inferred to be an `FnMut` closure.
146 fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
5e7ed085
FG
147 if let Some(ty::ReFree(free_region)) = self.to_error_region(fr).as_deref()
148 && let ty::BoundRegionKind::BrEnv = free_region.bound_region
149 && let DefiningTy::Closure(_, substs) = self.regioncx.universal_regions().defining_ty
150 {
151 return substs.as_closure().kind() == ty::ClosureKind::FnMut;
8faf50e0
XL
152 }
153
dfeec247 154 false
8faf50e0
XL
155 }
156
dfeec247 157 /// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`.
c295e0f8 158 pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
dfeec247
XL
159 // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are
160 // buffered in the `MirBorrowckCtxt`.
161
162 let mut outlives_suggestion = OutlivesSuggestionBuilder::default();
163
164 for nll_error in nll_errors.into_iter() {
165 match nll_error {
166 RegionErrorKind::TypeTestError { type_test } => {
167 // Try to convert the lower-bound region into something named we can print for the user.
168 let lower_bound_region = self.to_error_region(type_test.lower_bound);
169
170 let type_test_span = type_test.locations.span(&self.body);
171
172 if let Some(lower_bound_region) = lower_bound_region {
04454e1e
FG
173 let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx);
174 let origin = RelateParamBound(type_test_span, generic_ty, None);
5099ac24
FG
175 self.buffer_error(self.infcx.construct_generic_bound_failure(
176 type_test_span,
04454e1e 177 Some(origin),
5099ac24
FG
178 type_test.generic_kind,
179 lower_bound_region,
04454e1e 180 self.body.source.def_id().as_local(),
5099ac24 181 ));
dfeec247
XL
182 } else {
183 // FIXME. We should handle this case better. It
184 // indicates that we have e.g., some region variable
185 // whose value is like `'a+'b` where `'a` and `'b` are
5e7ed085 186 // distinct unrelated universal regions that are not
dfeec247
XL
187 // known to outlive one another. It'd be nice to have
188 // some examples where this arises to decide how best
189 // to report it; we could probably handle it by
190 // iterating over the universal regions and reporting
191 // an error that multiple bounds are required.
5099ac24
FG
192 self.buffer_error(self.infcx.tcx.sess.struct_span_err(
193 type_test_span,
194 &format!("`{}` does not live long enough", type_test.generic_kind),
195 ));
8faf50e0
XL
196 }
197 }
8faf50e0 198
74b04a01 199 RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => {
74b04a01
XL
200 let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
201 let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
5099ac24 202 self.buffer_error(unexpected_hidden_region_diagnostic(
dfeec247 203 self.infcx.tcx,
74b04a01
XL
204 span,
205 named_ty,
206 named_region,
5099ac24 207 ));
8faf50e0 208 }
e74abb32 209
dfeec247
XL
210 RegionErrorKind::BoundUniversalRegionError {
211 longer_fr,
94222f64 212 placeholder,
dfeec247
XL
213 error_element,
214 } => {
94222f64 215 let error_vid = self.regioncx.region_from_element(longer_fr, &error_element);
dfeec247
XL
216
217 // Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
c295e0f8 218 let (_, cause) = self.regioncx.find_outlives_blame_span(
dfeec247
XL
219 &self.body,
220 longer_fr,
94222f64
XL
221 NllRegionVariableOrigin::Placeholder(placeholder),
222 error_vid,
dfeec247
XL
223 );
224
94222f64
XL
225 let universe = placeholder.universe;
226 let universe_info = self.regioncx.universe_info(universe);
227
c295e0f8 228 universe_info.report_error(self, placeholder, error_element, cause);
dfeec247 229 }
e74abb32 230
dfeec247
XL
231 RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
232 if is_reported {
233 self.report_region_error(
234 longer_fr,
235 fr_origin,
236 shorter_fr,
237 &mut outlives_suggestion,
238 );
239 } else {
240 // We only report the first error, so as not to overwhelm the user. See
241 // `RegRegionErrorKind` docs.
242 //
243 // FIXME: currently we do nothing with these, but perhaps we can do better?
244 // FIXME: try collecting these constraints on the outlives suggestion
245 // builder. Does it make the suggestions any better?
246 debug!(
247 "Unreported region error: can't prove that {:?}: {:?}",
248 longer_fr, shorter_fr
249 );
250 }
251 }
8faf50e0
XL
252 }
253 }
254
dfeec247
XL
255 // Emit one outlives suggestions for each MIR def we borrowck
256 outlives_suggestion.add_suggestion(self);
8faf50e0
XL
257 }
258
8faf50e0
XL
259 /// Report an error because the universal region `fr` was required to outlive
260 /// `outlived_fr` but it is not known to do so. For example:
261 ///
04454e1e 262 /// ```compile_fail,E0312
8faf50e0
XL
263 /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
264 /// ```
265 ///
266 /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
c295e0f8 267 pub(crate) fn report_region_error(
dfeec247 268 &mut self,
8faf50e0 269 fr: RegionVid,
5869c6ff 270 fr_origin: NllRegionVariableOrigin,
8faf50e0 271 outlived_fr: RegionVid,
dfeec247
XL
272 outlives_suggestion: &mut OutlivesSuggestionBuilder,
273 ) {
274 debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
8faf50e0 275
c295e0f8 276 let BlameConstraint { category, cause, variance_info, from_closure: _ } =
dfeec247
XL
277 self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| {
278 self.regioncx.provides_universal_region(r, fr, outlived_fr)
279 });
8faf50e0 280
c295e0f8 281 debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
8faf50e0
XL
282 // Check if we can use one of the "nice region errors".
283 if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
c295e0f8 284 let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f);
9fa01778 285 if let Some(diag) = nice.try_report_from_nll() {
5099ac24 286 self.buffer_error(diag);
dfeec247 287 return;
8faf50e0
XL
288 }
289 }
290
291 let (fr_is_local, outlived_fr_is_local): (bool, bool) = (
dfeec247
XL
292 self.regioncx.universal_regions().is_local_free_region(fr),
293 self.regioncx.universal_regions().is_local_free_region(outlived_fr),
8faf50e0 294 );
0bf4aa26 295
a1dfa0c6 296 debug!(
dfeec247 297 "report_region_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
a1dfa0c6
XL
298 fr_is_local, outlived_fr_is_local, category
299 );
e1599b0c 300
e1599b0c 301 let errci = ErrorConstraintInfo {
dfeec247
XL
302 fr,
303 outlived_fr,
304 fr_is_local,
305 outlived_fr_is_local,
306 category,
c295e0f8 307 span: cause.span,
e1599b0c
XL
308 };
309
17df50a5 310 let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
f035d41b
XL
311 (ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => {
312 self.report_fnmut_error(&errci, kind)
a1dfa0c6
XL
313 }
314 (ConstraintCategory::Assignment, true, false)
60c5eb7d 315 | (ConstraintCategory::CallArgument, true, false) => {
dfeec247 316 let mut db = self.report_escaping_data_error(&errci);
60c5eb7d 317
dfeec247 318 outlives_suggestion.intermediate_suggestion(self, &errci, &mut db);
60c5eb7d
XL
319 outlives_suggestion.collect_constraint(fr, outlived_fr);
320
321 db
322 }
323 _ => {
dfeec247 324 let mut db = self.report_general_error(&errci);
60c5eb7d 325
dfeec247 326 outlives_suggestion.intermediate_suggestion(self, &errci, &mut db);
60c5eb7d
XL
327 outlives_suggestion.collect_constraint(fr, outlived_fr);
328
329 db
330 }
a1dfa0c6 331 };
dfeec247 332
17df50a5
XL
333 match variance_info {
334 ty::VarianceDiagInfo::None => {}
a2a8927a
XL
335 ty::VarianceDiagInfo::Invariant { ty, param_index } => {
336 let (desc, note) = match ty.kind() {
337 ty::RawPtr(ty_mut) => {
338 assert_eq!(ty_mut.mutbl, rustc_hir::Mutability::Mut);
339 (
04454e1e 340 format!("a mutable pointer to `{}`", ty_mut.ty),
a2a8927a
XL
341 "mutable pointers are invariant over their type parameter".to_string(),
342 )
343 }
344 ty::Ref(_, inner_ty, mutbl) => {
345 assert_eq!(*mutbl, rustc_hir::Mutability::Mut);
346 (
04454e1e 347 format!("a mutable reference to `{inner_ty}`"),
a2a8927a
XL
348 "mutable references are invariant over their type parameter"
349 .to_string(),
350 )
351 }
352 ty::Adt(adt, substs) => {
353 let generic_arg = substs[param_index as usize];
354 let identity_substs =
5e7ed085
FG
355 InternalSubsts::identity_for_item(self.infcx.tcx, adt.did());
356 let base_ty = self.infcx.tcx.mk_adt(*adt, identity_substs);
a2a8927a
XL
357 let base_generic_arg = identity_substs[param_index as usize];
358 let adt_desc = adt.descr();
359
360 let desc = format!(
04454e1e 361 "the type `{ty}`, which makes the generic argument `{generic_arg}` invariant"
a2a8927a
XL
362 );
363 let note = format!(
04454e1e
FG
364 "the {adt_desc} `{base_ty}` is invariant over the parameter `{base_generic_arg}`"
365 );
366 (desc, note)
367 }
368 ty::FnDef(def_id, _) => {
369 let name = self.infcx.tcx.item_name(*def_id);
370 let identity_substs =
371 InternalSubsts::identity_for_item(self.infcx.tcx, *def_id);
372 let desc = format!("a function pointer to `{name}`");
373 let note = format!(
374 "the function `{name}` is invariant over the parameter `{}`",
375 identity_substs[param_index as usize]
a2a8927a
XL
376 );
377 (desc, note)
378 }
379 _ => panic!("Unexpected type {:?}", ty),
17df50a5 380 };
a2a8927a
XL
381 diag.note(&format!("requirement occurs because of {desc}",));
382 diag.note(&note);
17df50a5
XL
383 diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance");
384 }
385 }
386
5099ac24 387 self.buffer_error(diag);
a1dfa0c6
XL
388 }
389
0bf4aa26
XL
390 /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
391 /// This function expects `fr` to be local and `outlived_fr` to not be local.
392 ///
393 /// ```text
394 /// error: captured variable cannot escape `FnMut` closure body
395 /// --> $DIR/issue-53040.rs:15:8
396 /// |
397 /// LL | || &mut v;
398 /// | -- ^^^^^^ creates a reference to a captured variable which escapes the closure body
399 /// | |
400 /// | inferred to be a `FnMut` closure
401 /// |
402 /// = note: `FnMut` closures only have access to their captured variables while they are
403 /// executing...
404 /// = note: ...therefore, returned references to captured variables will escape the closure
405 /// ```
f035d41b
XL
406 fn report_fnmut_error(
407 &self,
408 errci: &ErrorConstraintInfo,
409 kind: ReturnConstraint,
5e7ed085 410 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
dfeec247 411 let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
e1599b0c 412
dfeec247 413 let mut diag = self
e1599b0c 414 .infcx
a1dfa0c6
XL
415 .tcx
416 .sess
e1599b0c 417 .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
0bf4aa26 418
f035d41b 419 let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
1b1a35ee 420 if let ty::Opaque(def_id, _) = *output_ty.kind() {
f035d41b
XL
421 output_ty = self.infcx.tcx.type_of(def_id)
422 };
423
424 debug!("report_fnmut_error: output_ty={:?}", output_ty);
425
1b1a35ee 426 let message = match output_ty.kind() {
f035d41b
XL
427 ty::Closure(_, _) => {
428 "returns a closure that contains a reference to a captured variable, which then \
429 escapes the closure body"
430 }
5e7ed085 431 ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) => {
f035d41b
XL
432 "returns an `async` block that contains a reference to a captured variable, which then \
433 escapes the closure body"
434 }
435 _ => "returns a reference to a captured variable which escapes the closure body",
0bf4aa26
XL
436 };
437
e1599b0c 438 diag.span_label(*span, message);
0bf4aa26 439
5099ac24 440 if let ReturnConstraint::ClosureUpvar(upvar_field) = kind {
f035d41b
XL
441 let def_id = match self.regioncx.universal_regions().defining_ty {
442 DefiningTy::Closure(def_id, _) => def_id,
1b1a35ee 443 ty => bug!("unexpected DefiningTy {:?}", ty),
f035d41b
XL
444 };
445
5099ac24
FG
446 let captured_place = &self.upvars[upvar_field.index()].place;
447 let defined_hir = match captured_place.place.base {
448 PlaceBase::Local(hirid) => Some(hirid),
449 PlaceBase::Upvar(upvar) => Some(upvar.var_path.hir_id),
450 _ => None,
451 };
452
453 if defined_hir.is_some() {
454 let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap();
455 let upvar_def_span = self.infcx.tcx.hir().span(defined_hir.unwrap());
456 let upvar_span = upvars_map.get(&defined_hir.unwrap()).unwrap().span;
457 diag.span_label(upvar_def_span, "variable defined here");
458 diag.span_label(upvar_span, "variable captured here");
459 }
f035d41b
XL
460 }
461
3dfed10e
XL
462 if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
463 diag.span_label(fr_span, "inferred to be a `FnMut` closure");
0bf4aa26
XL
464 }
465
a1dfa0c6
XL
466 diag.note(
467 "`FnMut` closures only have access to their captured variables while they are \
468 executing...",
469 );
0bf4aa26
XL
470 diag.note("...therefore, they cannot allow references to captured variables to escape");
471
e1599b0c 472 diag
0bf4aa26
XL
473 }
474
94222f64 475 /// Reports an error specifically for when data is escaping a closure.
0bf4aa26
XL
476 ///
477 /// ```text
478 /// error: borrowed data escapes outside of function
479 /// --> $DIR/lifetime-bound-will-change-warning.rs:44:5
480 /// |
481 /// LL | fn test2<'a>(x: &'a Box<Fn()+'a>) {
482 /// | - `x` is a reference that is only valid in the function body
483 /// LL | // but ref_obj will not, so warn.
484 /// LL | ref_obj(x)
485 /// | ^^^^^^^^^^ `x` escapes the function body here
486 /// ```
5e7ed085
FG
487 fn report_escaping_data_error(
488 &self,
489 errci: &ErrorConstraintInfo,
490 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
dfeec247
XL
491 let ErrorConstraintInfo { span, category, .. } = errci;
492
493 let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
494 self.infcx.tcx,
495 &self.body,
496 &self.local_names,
497 &self.upvars,
498 errci.fr,
499 );
500 let outlived_fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
501 self.infcx.tcx,
502 &self.body,
503 &self.local_names,
504 &self.upvars,
60c5eb7d
XL
505 errci.outlived_fr,
506 );
8faf50e0 507
74b04a01
XL
508 let (_, escapes_from) = self
509 .infcx
510 .tcx
511 .article_and_description(self.regioncx.universal_regions().defining_ty.def_id());
8faf50e0 512
0bf4aa26
XL
513 // Revert to the normal error in these cases.
514 // Assignments aren't "escapes" in function items.
515 if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none())
74b04a01
XL
516 || (*category == ConstraintCategory::Assignment
517 && self.regioncx.universal_regions().defining_ty.is_fn_def())
518 || self.regioncx.universal_regions().defining_ty.is_const()
0bf4aa26 519 {
dfeec247
XL
520 return self.report_general_error(&ErrorConstraintInfo {
521 fr_is_local: true,
522 outlived_fr_is_local: false,
523 ..*errci
524 });
8faf50e0
XL
525 }
526
dfeec247
XL
527 let mut diag =
528 borrowck_errors::borrowed_data_escapes_closure(self.infcx.tcx, *span, escapes_from);
8faf50e0 529
0bf4aa26
XL
530 if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
531 diag.span_label(
532 outlived_fr_span,
04454e1e 533 format!("`{outlived_fr_name}` declared here, outside of the {escapes_from} body",),
0bf4aa26 534 );
8faf50e0
XL
535 }
536
0bf4aa26
XL
537 if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
538 diag.span_label(
539 fr_span,
540 format!(
04454e1e 541 "`{fr_name}` is a reference that is only valid in the {escapes_from} body",
0bf4aa26
XL
542 ),
543 );
8faf50e0 544
04454e1e 545 diag.span_label(*span, format!("`{fr_name}` escapes the {escapes_from} body here"));
8faf50e0
XL
546 }
547
c295e0f8
XL
548 // Only show an extra note if we can find an 'error region' for both of the region
549 // variables. This avoids showing a noisy note that just mentions 'synthetic' regions
550 // that don't help the user understand the error.
551 if self.to_error_region(errci.fr).is_some()
552 && self.to_error_region(errci.outlived_fr).is_some()
553 {
554 let fr_region_name = self.give_region_a_name(errci.fr).unwrap();
555 fr_region_name.highlight_region_name(&mut diag);
556 let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
557 outlived_fr_region_name.highlight_region_name(&mut diag);
558
559 diag.span_label(
560 *span,
561 format!(
562 "{}requires that `{}` must outlive `{}`",
563 category.description(),
564 fr_region_name,
565 outlived_fr_region_name,
566 ),
567 );
568 }
e1599b0c 569 diag
8faf50e0
XL
570 }
571
0bf4aa26
XL
572 /// Reports a region inference error for the general case with named/synthesized lifetimes to
573 /// explain what is happening.
574 ///
575 /// ```text
576 /// error: unsatisfied lifetime constraints
577 /// --> $DIR/regions-creating-enums3.rs:17:5
578 /// |
579 /// LL | fn mk_add_bad1<'a,'b>(x: &'a ast<'a>, y: &'b ast<'b>) -> ast<'a> {
580 /// | -- -- lifetime `'b` defined here
581 /// | |
582 /// | lifetime `'a` defined here
583 /// LL | ast::add(x, y)
584 /// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
585 /// | is returning data with lifetime `'b`
586 /// ```
5e7ed085
FG
587 fn report_general_error(
588 &self,
589 errci: &ErrorConstraintInfo,
590 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
e1599b0c 591 let ErrorConstraintInfo {
dfeec247
XL
592 fr,
593 fr_is_local,
594 outlived_fr,
595 outlived_fr_is_local,
596 span,
597 category,
598 ..
e1599b0c
XL
599 } = errci;
600
dfeec247
XL
601 let mut diag =
602 self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough");
8faf50e0 603
29967ef6
XL
604 let (_, mir_def_name) =
605 self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id());
8faf50e0 606
dfeec247 607 let fr_name = self.give_region_a_name(*fr).unwrap();
e1599b0c 608 fr_name.highlight_region_name(&mut diag);
dfeec247 609 let outlived_fr_name = self.give_region_a_name(*outlived_fr).unwrap();
e1599b0c
XL
610 outlived_fr_name.highlight_region_name(&mut diag);
611
8faf50e0 612 match (category, outlived_fr_is_local, fr_is_local) {
f035d41b 613 (ConstraintCategory::Return(_), true, _) => {
a1dfa0c6 614 diag.span_label(
e1599b0c 615 *span,
a1dfa0c6 616 format!(
04454e1e
FG
617 "{mir_def_name} was supposed to return data with lifetime `{outlived_fr_name}` but it is returning \
618 data with lifetime `{fr_name}`",
a1dfa0c6
XL
619 ),
620 );
621 }
8faf50e0 622 _ => {
a1dfa0c6 623 diag.span_label(
e1599b0c 624 *span,
a1dfa0c6
XL
625 format!(
626 "{}requires that `{}` must outlive `{}`",
627 category.description(),
628 fr_name,
629 outlived_fr_name,
630 ),
631 );
632 }
8faf50e0
XL
633 }
634
dfeec247 635 self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
04454e1e 636 self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
0bf4aa26 637
e1599b0c 638 diag
8faf50e0
XL
639 }
640
94222f64 641 /// Adds a suggestion to errors where an `impl Trait` is returned.
0bf4aa26
XL
642 ///
643 /// ```text
dc9dc135 644 /// help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as
0bf4aa26
XL
645 /// a constraint
646 /// |
647 /// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
648 /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
649 /// ```
650 fn add_static_impl_trait_suggestion(
651 &self,
5e7ed085 652 diag: &mut Diagnostic,
0bf4aa26
XL
653 fr: RegionVid,
654 // We need to pass `fr_name` - computing it again will label it twice.
655 fr_name: RegionName,
656 outlived_fr: RegionVid,
657 ) {
04454e1e
FG
658 if let (Some(f), Some(outlived_f)) =
659 (self.to_error_region(fr), self.to_error_region(outlived_fr))
a1dfa0c6 660 {
04454e1e
FG
661 if *outlived_f != ty::ReStatic {
662 return;
663 }
664
665 let fn_returns = self
dfeec247 666 .infcx
a1dfa0c6
XL
667 .tcx
668 .is_suitable_region(f)
04454e1e
FG
669 .map(|r| self.infcx.tcx.return_type_impl_or_dyn_traits(r.def_id))
670 .unwrap_or_default();
0bf4aa26 671
04454e1e
FG
672 if fn_returns.is_empty() {
673 return;
0bf4aa26 674 }
04454e1e
FG
675
676 let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) {
677 param
678 } else {
679 return;
680 };
681
682 let lifetime = if f.has_name() { fr_name.to_string() } else { "'_".to_string() };
683
684 let arg = match param.param.pat.simple_ident() {
685 Some(simple_ident) => format!("argument `{}`", simple_ident),
686 None => "the argument".to_string(),
687 };
688 let captures = format!("captures data from {}", arg);
689
690 return nice_region_error::suggest_new_region_bound(
691 self.infcx.tcx,
692 diag,
693 fn_returns,
694 lifetime,
695 Some(arg),
696 captures,
697 Some((param.param_ty_span, param.param_ty.to_string())),
698 );
0bf4aa26
XL
699 }
700 }
04454e1e
FG
701
702 fn suggest_adding_lifetime_params(
703 &self,
704 diag: &mut Diagnostic,
705 sub: RegionVid,
706 sup: RegionVid,
707 ) {
708 let (Some(sub), Some(sup)) = (self.to_error_region(sub), self.to_error_region(sup)) else {
709 return
710 };
711
712 let Some((ty_sub, _)) = self
713 .infcx
714 .tcx
715 .is_suitable_region(sub)
716 .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sub, &anon_reg.boundregion)) else {
717 return
718 };
719
720 let Some((ty_sup, _)) = self
721 .infcx
722 .tcx
723 .is_suitable_region(sup)
724 .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sup, &anon_reg.boundregion)) else {
725 return
726 };
727
728 suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
729 }
8faf50e0 730}