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