]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
more centril nits
[rust.git] / src / librustc_mir / borrow_check / nll / region_infer / error_reporting / mod.rs
1 use crate::borrow_check::nll::constraints::OutlivesConstraint;
2 use crate::borrow_check::nll::region_infer::AppliedMemberConstraint;
3 use crate::borrow_check::nll::region_infer::RegionInferenceContext;
4 use crate::borrow_check::nll::type_check::Locations;
5 use crate::borrow_check::nll::universal_regions::DefiningTy;
6 use crate::borrow_check::nll::ConstraintDescription;
7 use crate::util::borrowck_errors::{BorrowckErrors, Origin};
8 use crate::borrow_check::Upvar;
9 use rustc::hir::def_id::DefId;
10 use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
11 use rustc::infer::InferCtxt;
12 use rustc::infer::NLLRegionVariableOrigin;
13 use rustc::mir::{ConstraintCategory, Location, Body};
14 use rustc::ty::{self, RegionVid};
15 use rustc_data_structures::indexed_vec::IndexVec;
16 use rustc_errors::{Diagnostic, DiagnosticBuilder};
17 use std::collections::VecDeque;
18 use syntax::errors::Applicability;
19 use syntax::symbol::kw;
20 use syntax_pos::Span;
21
22 mod region_name;
23 mod var_name;
24
25 crate use self::region_name::{RegionName, RegionNameSource};
26
27 impl ConstraintDescription for ConstraintCategory {
28     fn description(&self) -> &'static str {
29         // Must end with a space. Allows for empty names to be provided.
30         match self {
31             ConstraintCategory::Assignment => "assignment ",
32             ConstraintCategory::Return => "returning this value ",
33             ConstraintCategory::Yield => "yielding this value ",
34             ConstraintCategory::UseAsConst => "using this value as a constant ",
35             ConstraintCategory::UseAsStatic => "using this value as a static ",
36             ConstraintCategory::Cast => "cast ",
37             ConstraintCategory::CallArgument => "argument ",
38             ConstraintCategory::TypeAnnotation => "type annotation ",
39             ConstraintCategory::ClosureBounds => "closure body ",
40             ConstraintCategory::SizedBound => "proving this value is `Sized` ",
41             ConstraintCategory::CopyBound => "copying this value ",
42             ConstraintCategory::OpaqueType => "opaque type ",
43             ConstraintCategory::Boring
44             | ConstraintCategory::BoringNoLocation
45             | ConstraintCategory::Internal => "",
46         }
47     }
48 }
49
50 #[derive(Copy, Clone, PartialEq, Eq)]
51 enum Trace {
52     StartRegion,
53     FromOutlivesConstraint(OutlivesConstraint),
54     NotVisited,
55 }
56
57 impl<'tcx> RegionInferenceContext<'tcx> {
58     /// Tries to find the best constraint to blame for the fact that
59     /// `R: from_region`, where `R` is some region that meets
60     /// `target_test`. This works by following the constraint graph,
61     /// creating a constraint path that forces `R` to outlive
62     /// `from_region`, and then finding the best choices within that
63     /// path to blame.
64     fn best_blame_constraint(
65         &self,
66         body: &Body<'tcx>,
67         from_region: RegionVid,
68         target_test: impl Fn(RegionVid) -> bool,
69     ) -> (ConstraintCategory, bool, Span) {
70         debug!("best_blame_constraint(from_region={:?})", from_region);
71
72         // Find all paths
73         let (path, target_region) =
74             self.find_constraint_paths_between_regions(from_region, target_test)
75                 .unwrap();
76         debug!(
77             "best_blame_constraint: path={:#?}",
78             path.iter()
79                 .map(|&c| format!(
80                     "{:?} ({:?}: {:?})",
81                     c,
82                     self.constraint_sccs.scc(c.sup),
83                     self.constraint_sccs.scc(c.sub),
84                 ))
85                 .collect::<Vec<_>>()
86         );
87
88         // Classify each of the constraints along the path.
89         let mut categorized_path: Vec<(ConstraintCategory, bool, Span)> = path.iter()
90             .map(|constraint| {
91                 if constraint.category == ConstraintCategory::ClosureBounds {
92                     self.retrieve_closure_constraint_info(body, &constraint)
93                 } else {
94                     (constraint.category, false, constraint.locations.span(body))
95                 }
96             })
97             .collect();
98         debug!(
99             "best_blame_constraint: categorized_path={:#?}",
100             categorized_path
101         );
102
103         // To find the best span to cite, we first try to look for the
104         // final constraint that is interesting and where the `sup` is
105         // not unified with the ultimate target region. The reason
106         // for this is that we have a chain of constraints that lead
107         // from the source to the target region, something like:
108         //
109         //    '0: '1 ('0 is the source)
110         //    '1: '2
111         //    '2: '3
112         //    '3: '4
113         //    '4: '5
114         //    '5: '6 ('6 is the target)
115         //
116         // Some of those regions are unified with `'6` (in the same
117         // SCC).  We want to screen those out. After that point, the
118         // "closest" constraint we have to the end is going to be the
119         // most likely to be the point where the value escapes -- but
120         // we still want to screen for an "interesting" point to
121         // highlight (e.g., a call site or something).
122         let target_scc = self.constraint_sccs.scc(target_region);
123         let best_choice = (0..path.len()).rev().find(|&i| {
124             let constraint = path[i];
125
126             let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
127
128             match categorized_path[i].0 {
129                 ConstraintCategory::OpaqueType | ConstraintCategory::Boring |
130                 ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => false,
131                 ConstraintCategory::TypeAnnotation | ConstraintCategory::Return |
132                 ConstraintCategory::Yield => true,
133                 _ => constraint_sup_scc != target_scc,
134             }
135         });
136         if let Some(i) = best_choice {
137             if let Some(next) = categorized_path.get(i + 1) {
138                 if categorized_path[i].0 == ConstraintCategory::Return
139                     && next.0 == ConstraintCategory::OpaqueType
140                 {
141                     // The return expression is being influenced by the return type being
142                     // impl Trait, point at the return type and not the return expr.
143                     return *next;
144                 }
145             }
146             return categorized_path[i];
147         }
148
149         // If that search fails, that is.. unusual. Maybe everything
150         // is in the same SCC or something. In that case, find what
151         // appears to be the most interesting point to report to the
152         // user via an even more ad-hoc guess.
153         categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
154         debug!("`: sorted_path={:#?}", categorized_path);
155
156         *categorized_path.first().unwrap()
157     }
158
159     /// Walks the graph of constraints (where `'a: 'b` is considered
160     /// an edge `'a -> 'b`) to find all paths from `from_region` to
161     /// `to_region`. The paths are accumulated into the vector
162     /// `results`. The paths are stored as a series of
163     /// `ConstraintIndex` values -- in other words, a list of *edges*.
164     ///
165     /// Returns: a series of constraints as well as the region `R`
166     /// that passed the target test.
167     fn find_constraint_paths_between_regions(
168         &self,
169         from_region: RegionVid,
170         target_test: impl Fn(RegionVid) -> bool,
171     ) -> Option<(Vec<OutlivesConstraint>, RegionVid)> {
172         let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions);
173         context[from_region] = Trace::StartRegion;
174
175         // Use a deque so that we do a breadth-first search. We will
176         // stop at the first match, which ought to be the shortest
177         // path (fewest constraints).
178         let mut deque = VecDeque::new();
179         deque.push_back(from_region);
180
181         while let Some(r) = deque.pop_front() {
182             debug!(
183                 "find_constraint_paths_between_regions: from_region={:?} r={:?} value={}",
184                 from_region,
185                 r,
186                 self.region_value_str(r),
187             );
188
189             // Check if we reached the region we were looking for. If so,
190             // we can reconstruct the path that led to it and return it.
191             if target_test(r) {
192                 let mut result = vec![];
193                 let mut p = r;
194                 loop {
195                     match context[p] {
196                         Trace::NotVisited => {
197                             bug!("found unvisited region {:?} on path to {:?}", p, r)
198                         }
199
200                         Trace::FromOutlivesConstraint(c) => {
201                             result.push(c);
202                             p = c.sup;
203                         }
204
205                         Trace::StartRegion => {
206                             result.reverse();
207                             return Some((result, r));
208                         }
209                     }
210                 }
211             }
212
213             // Otherwise, walk over the outgoing constraints and
214             // enqueue any regions we find, keeping track of how we
215             // reached them.
216
217             // A constraint like `'r: 'x` can come from our constraint
218             // graph.
219             let fr_static = self.universal_regions.fr_static;
220             let outgoing_edges_from_graph = self.constraint_graph
221                 .outgoing_edges(r, &self.constraints, fr_static);
222
223
224             // But member constraints can also give rise to `'r: 'x`
225             // edges that were not part of the graph initially, so
226             // watch out for those.
227             let outgoing_edges_from_picks = self.applied_member_constraints(r)
228                 .iter()
229                 .map(|&AppliedMemberConstraint { min_choice, member_constraint_index, .. }| {
230                     let p_c = &self.member_constraints[member_constraint_index];
231                     OutlivesConstraint {
232                         sup: r,
233                         sub: min_choice,
234                         locations: Locations::All(p_c.definition_span),
235                         category: ConstraintCategory::OpaqueType,
236                     }
237                 });
238
239             for constraint in outgoing_edges_from_graph.chain(outgoing_edges_from_picks) {
240                 debug_assert_eq!(constraint.sup, r);
241                 let sub_region = constraint.sub;
242                 if let Trace::NotVisited = context[sub_region] {
243                     context[sub_region] = Trace::FromOutlivesConstraint(constraint);
244                     deque.push_back(sub_region);
245                 }
246             }
247         }
248
249         None
250     }
251
252     /// Report an error because the universal region `fr` was required to outlive
253     /// `outlived_fr` but it is not known to do so. For example:
254     ///
255     /// ```
256     /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
257     /// ```
258     ///
259     /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
260     pub(super) fn report_error(
261         &self,
262         body: &Body<'tcx>,
263         upvars: &[Upvar],
264         infcx: &InferCtxt<'_, 'tcx>,
265         mir_def_id: DefId,
266         fr: RegionVid,
267         outlived_fr: RegionVid,
268         errors_buffer: &mut Vec<Diagnostic>,
269     ) {
270         debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
271
272         let (category, _, span) = self.best_blame_constraint(body, fr, |r| {
273             self.provides_universal_region(r, fr, outlived_fr)
274         });
275
276         debug!("report_error: category={:?} {:?}", category, span);
277         // Check if we can use one of the "nice region errors".
278         if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
279             let tables = infcx.tcx.typeck_tables_of(mir_def_id);
280             let nice = NiceRegionError::new_from_span(infcx, span, o, f, Some(tables));
281             if let Some(diag) = nice.try_report_from_nll() {
282                 diag.buffer(errors_buffer);
283                 return;
284             }
285         }
286
287         let (fr_is_local, outlived_fr_is_local): (bool, bool) = (
288             self.universal_regions.is_local_free_region(fr),
289             self.universal_regions.is_local_free_region(outlived_fr),
290         );
291
292         debug!(
293             "report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
294             fr_is_local, outlived_fr_is_local, category
295         );
296         match (category, fr_is_local, outlived_fr_is_local) {
297             (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) => {
298                 self.report_fnmut_error(
299                     body,
300                     upvars,
301                     infcx,
302                     mir_def_id,
303                     fr,
304                     outlived_fr,
305                     span,
306                     errors_buffer,
307                 )
308             }
309             (ConstraintCategory::Assignment, true, false)
310             | (ConstraintCategory::CallArgument, true, false) => self.report_escaping_data_error(
311                 body,
312                 upvars,
313                 infcx,
314                 mir_def_id,
315                 fr,
316                 outlived_fr,
317                 category,
318                 span,
319                 errors_buffer,
320             ),
321             _ => self.report_general_error(
322                 body,
323                 upvars,
324                 infcx,
325                 mir_def_id,
326                 fr,
327                 fr_is_local,
328                 outlived_fr,
329                 outlived_fr_is_local,
330                 category,
331                 span,
332                 errors_buffer,
333             ),
334         };
335     }
336
337     /// We have a constraint `fr1: fr2` that is not satisfied, where
338     /// `fr2` represents some universal region. Here, `r` is some
339     /// region where we know that `fr1: r` and this function has the
340     /// job of determining whether `r` is "to blame" for the fact that
341     /// `fr1: fr2` is required.
342     ///
343     /// This is true under two conditions:
344     ///
345     /// - `r == fr2`
346     /// - `fr2` is `'static` and `r` is some placeholder in a universe
347     ///   that cannot be named by `fr1`; in that case, we will require
348     ///   that `fr1: 'static` because it is the only way to `fr1: r` to
349     ///   be satisfied. (See `add_incompatible_universe`.)
350     fn provides_universal_region(&self, r: RegionVid, fr1: RegionVid, fr2: RegionVid) -> bool {
351         debug!(
352             "provides_universal_region(r={:?}, fr1={:?}, fr2={:?})",
353             r, fr1, fr2
354         );
355         let result = {
356             r == fr2 || {
357                 fr2 == self.universal_regions.fr_static && self.cannot_name_placeholder(fr1, r)
358             }
359         };
360         debug!("provides_universal_region: result = {:?}", result);
361         result
362     }
363
364     /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
365     /// This function expects `fr` to be local and `outlived_fr` to not be local.
366     ///
367     /// ```text
368     /// error: captured variable cannot escape `FnMut` closure body
369     ///   --> $DIR/issue-53040.rs:15:8
370     ///    |
371     /// LL |     || &mut v;
372     ///    |     -- ^^^^^^ creates a reference to a captured variable which escapes the closure body
373     ///    |     |
374     ///    |     inferred to be a `FnMut` closure
375     ///    |
376     ///    = note: `FnMut` closures only have access to their captured variables while they are
377     ///            executing...
378     ///    = note: ...therefore, returned references to captured variables will escape the closure
379     /// ```
380     fn report_fnmut_error(
381         &self,
382         body: &Body<'tcx>,
383         upvars: &[Upvar],
384         infcx: &InferCtxt<'_, 'tcx>,
385         mir_def_id: DefId,
386         _fr: RegionVid,
387         outlived_fr: RegionVid,
388         span: Span,
389         errors_buffer: &mut Vec<Diagnostic>,
390     ) {
391         let mut diag = infcx
392             .tcx
393             .sess
394             .struct_span_err(span, "captured variable cannot escape `FnMut` closure body");
395
396         // We should check if the return type of this closure is in fact a closure - in that
397         // case, we can special case the error further.
398         let return_type_is_closure = self.universal_regions.unnormalized_output_ty.is_closure();
399         let message = if return_type_is_closure {
400             "returns a closure that contains a reference to a captured variable, which then \
401              escapes the closure body"
402         } else {
403             "returns a reference to a captured variable which escapes the closure body"
404         };
405
406         diag.span_label(span, message);
407
408         match self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, &mut 1)
409             .unwrap().source
410         {
411             RegionNameSource::NamedEarlyBoundRegion(fr_span)
412             | RegionNameSource::NamedFreeRegion(fr_span)
413             | RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
414             | RegionNameSource::CannotMatchHirTy(fr_span, _)
415             | RegionNameSource::MatchedHirTy(fr_span)
416             | RegionNameSource::MatchedAdtAndSegment(fr_span)
417             | RegionNameSource::AnonRegionFromUpvar(fr_span, _)
418             | RegionNameSource::AnonRegionFromOutput(fr_span, _, _) => {
419                 diag.span_label(fr_span, "inferred to be a `FnMut` closure");
420             }
421             _ => {}
422         }
423
424         diag.note(
425             "`FnMut` closures only have access to their captured variables while they are \
426              executing...",
427         );
428         diag.note("...therefore, they cannot allow references to captured variables to escape");
429
430         diag.buffer(errors_buffer);
431     }
432
433     /// Reports a error specifically for when data is escaping a closure.
434     ///
435     /// ```text
436     /// error: borrowed data escapes outside of function
437     ///   --> $DIR/lifetime-bound-will-change-warning.rs:44:5
438     ///    |
439     /// LL | fn test2<'a>(x: &'a Box<Fn()+'a>) {
440     ///    |              - `x` is a reference that is only valid in the function body
441     /// LL |     // but ref_obj will not, so warn.
442     /// LL |     ref_obj(x)
443     ///    |     ^^^^^^^^^^ `x` escapes the function body here
444     /// ```
445     fn report_escaping_data_error(
446         &self,
447         body: &Body<'tcx>,
448         upvars: &[Upvar],
449         infcx: &InferCtxt<'_, 'tcx>,
450         mir_def_id: DefId,
451         fr: RegionVid,
452         outlived_fr: RegionVid,
453         category: ConstraintCategory,
454         span: Span,
455         errors_buffer: &mut Vec<Diagnostic>,
456     ) {
457         let fr_name_and_span =
458             self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, fr);
459         let outlived_fr_name_and_span =
460             self.get_var_name_and_span_for_region(infcx.tcx, body, upvars, outlived_fr);
461
462         let escapes_from = match self.universal_regions.defining_ty {
463             DefiningTy::Closure(..) => "closure",
464             DefiningTy::Generator(..) => "generator",
465             DefiningTy::FnDef(..) => "function",
466             DefiningTy::Const(..) => "const",
467         };
468
469         // Revert to the normal error in these cases.
470         // Assignments aren't "escapes" in function items.
471         if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none())
472             || (category == ConstraintCategory::Assignment && escapes_from == "function")
473             || escapes_from == "const"
474         {
475             return self.report_general_error(
476                 body,
477                 upvars,
478                 infcx,
479                 mir_def_id,
480                 fr,
481                 true,
482                 outlived_fr,
483                 false,
484                 category,
485                 span,
486                 errors_buffer,
487             );
488         }
489
490         let mut diag = infcx
491             .tcx
492             .borrowed_data_escapes_closure(span, escapes_from, Origin::Mir);
493
494         if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
495             diag.span_label(
496                 outlived_fr_span,
497                 format!(
498                     "`{}` is declared here, outside of the {} body",
499                     outlived_fr_name, escapes_from
500                 ),
501             );
502         }
503
504         if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
505             diag.span_label(
506                 fr_span,
507                 format!(
508                     "`{}` is a reference that is only valid in the {} body",
509                     fr_name, escapes_from
510                 ),
511             );
512
513             diag.span_label(
514                 span,
515                 format!("`{}` escapes the {} body here", fr_name, escapes_from),
516             );
517         }
518
519         diag.buffer(errors_buffer);
520     }
521
522     /// Reports a region inference error for the general case with named/synthesized lifetimes to
523     /// explain what is happening.
524     ///
525     /// ```text
526     /// error: unsatisfied lifetime constraints
527     ///   --> $DIR/regions-creating-enums3.rs:17:5
528     ///    |
529     /// LL | fn mk_add_bad1<'a,'b>(x: &'a ast<'a>, y: &'b ast<'b>) -> ast<'a> {
530     ///    |                -- -- lifetime `'b` defined here
531     ///    |                |
532     ///    |                lifetime `'a` defined here
533     /// LL |     ast::add(x, y)
534     ///    |     ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
535     ///    |                    is returning data with lifetime `'b`
536     /// ```
537     fn report_general_error(
538         &self,
539         body: &Body<'tcx>,
540         upvars: &[Upvar],
541         infcx: &InferCtxt<'_, 'tcx>,
542         mir_def_id: DefId,
543         fr: RegionVid,
544         fr_is_local: bool,
545         outlived_fr: RegionVid,
546         outlived_fr_is_local: bool,
547         category: ConstraintCategory,
548         span: Span,
549         errors_buffer: &mut Vec<Diagnostic>,
550     ) {
551         let mut diag = infcx.tcx.sess.struct_span_err(
552             span,
553             "lifetime may not live long enough"
554         );
555
556         let counter = &mut 1;
557         let fr_name = self.give_region_a_name(
558             infcx, body, upvars, mir_def_id, fr, counter).unwrap();
559         fr_name.highlight_region_name(&mut diag);
560         let outlived_fr_name =
561             self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_fr, counter).unwrap();
562         outlived_fr_name.highlight_region_name(&mut diag);
563
564         let mir_def_name = if infcx.tcx.is_closure(mir_def_id) {
565             "closure"
566         } else {
567             "function"
568         };
569
570         match (category, outlived_fr_is_local, fr_is_local) {
571             (ConstraintCategory::Return, true, _) => {
572                 diag.span_label(
573                     span,
574                     format!(
575                         "{} was supposed to return data with lifetime `{}` but it is returning \
576                          data with lifetime `{}`",
577                         mir_def_name, outlived_fr_name, fr_name
578                     ),
579                 );
580             }
581             _ => {
582                 diag.span_label(
583                     span,
584                     format!(
585                         "{}requires that `{}` must outlive `{}`",
586                         category.description(),
587                         fr_name,
588                         outlived_fr_name,
589                     ),
590                 );
591             }
592         }
593
594         self.add_static_impl_trait_suggestion(infcx, &mut diag, fr, fr_name, outlived_fr);
595
596         diag.buffer(errors_buffer);
597     }
598
599     /// Adds a suggestion to errors where a `impl Trait` is returned.
600     ///
601     /// ```text
602     /// help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as
603     ///       a constraint
604     ///    |
605     /// LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
606     ///    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
607     /// ```
608     fn add_static_impl_trait_suggestion(
609         &self,
610         infcx: &InferCtxt<'_, 'tcx>,
611         diag: &mut DiagnosticBuilder<'_>,
612         fr: RegionVid,
613         // We need to pass `fr_name` - computing it again will label it twice.
614         fr_name: RegionName,
615         outlived_fr: RegionVid,
616     ) {
617         if let (Some(f), Some(ty::RegionKind::ReStatic)) =
618             (self.to_error_region(fr), self.to_error_region(outlived_fr))
619         {
620             if let Some(ty::TyS {
621                 sty: ty::Opaque(did, substs),
622                 ..
623             }) = infcx
624                 .tcx
625                 .is_suitable_region(f)
626                 .map(|r| r.def_id)
627                 .map(|id| infcx.tcx.return_type_impl_trait(id))
628                 .unwrap_or(None)
629             {
630                 // Check whether or not the impl trait return type is intended to capture
631                 // data with the static lifetime.
632                 //
633                 // eg. check for `impl Trait + 'static` instead of `impl Trait`.
634                 let has_static_predicate = {
635                     let predicates_of = infcx.tcx.predicates_of(*did);
636                     let bounds = predicates_of.instantiate(infcx.tcx, substs);
637
638                     let mut found = false;
639                     for predicate in bounds.predicates {
640                         if let ty::Predicate::TypeOutlives(binder) = predicate {
641                             if let ty::OutlivesPredicate(_, ty::RegionKind::ReStatic) =
642                                 binder.skip_binder()
643                             {
644                                 found = true;
645                                 break;
646                             }
647                         }
648                     }
649
650                     found
651                 };
652
653                 debug!(
654                     "add_static_impl_trait_suggestion: has_static_predicate={:?}",
655                     has_static_predicate
656                 );
657                 let static_str = kw::StaticLifetime;
658                 // If there is a static predicate, then the only sensible suggestion is to replace
659                 // fr with `'static`.
660                 if has_static_predicate {
661                     diag.help(&format!(
662                         "consider replacing `{}` with `{}`",
663                         fr_name, static_str,
664                     ));
665                 } else {
666                     // Otherwise, we should suggest adding a constraint on the return type.
667                     let span = infcx.tcx.def_span(*did);
668                     if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(span) {
669                         let suggestable_fr_name = if fr_name.was_named() {
670                             fr_name.to_string()
671                         } else {
672                             "'_".to_string()
673                         };
674
675                         diag.span_suggestion(
676                             span,
677                             &format!(
678                                 "to allow this `impl Trait` to capture borrowed data with lifetime \
679                                  `{}`, add `{}` as a constraint",
680                                 fr_name, suggestable_fr_name,
681                             ),
682                             format!("{} + {}", snippet, suggestable_fr_name),
683                             Applicability::MachineApplicable,
684                         );
685                     }
686                 }
687             }
688         }
689     }
690
691     crate fn free_region_constraint_info(
692         &self,
693         body: &Body<'tcx>,
694         upvars: &[Upvar],
695         mir_def_id: DefId,
696         infcx: &InferCtxt<'_, 'tcx>,
697         borrow_region: RegionVid,
698         outlived_region: RegionVid,
699     ) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
700         let (category, from_closure, span) = self.best_blame_constraint(
701             body,
702             borrow_region,
703             |r| self.provides_universal_region(r, borrow_region, outlived_region)
704         );
705         let outlived_fr_name =
706             self.give_region_a_name(infcx, body, upvars, mir_def_id, outlived_region, &mut 1);
707         (category, from_closure, span, outlived_fr_name)
708     }
709
710     // Finds some region R such that `fr1: R` and `R` is live at
711     // `elem`.
712     crate fn find_sub_region_live_at(
713         &self,
714         fr1: RegionVid,
715         elem: Location,
716     ) -> RegionVid {
717         debug!("find_sub_region_live_at(fr1={:?}, elem={:?})", fr1, elem);
718         self.find_constraint_paths_between_regions(fr1, |r| {
719             // First look for some `r` such that `fr1: r` and `r` is live at `elem`
720             debug!(
721                 "find_sub_region_live_at: liveness_constraints for {:?} are {:?}",
722                 r,
723                 self.liveness_constraints.region_value_str(r),
724             );
725             self.liveness_constraints.contains(r, elem)
726         }).or_else(|| {
727                 // If we fail to find that, we may find some `r` such that
728                 // `fr1: r` and `r` is a placeholder from some universe
729                 // `fr1` cannot name. This would force `fr1` to be
730                 // `'static`.
731                 self.find_constraint_paths_between_regions(fr1, |r| {
732                     self.cannot_name_placeholder(fr1, r)
733                 })
734             })
735             .or_else(|| {
736                 // If we fail to find THAT, it may be that `fr1` is a
737                 // placeholder that cannot "fit" into its SCC. In that
738                 // case, there should be some `r` where `fr1: r`, both
739                 // `fr1` and `r` are in the same SCC, and `fr1` is a
740                 // placeholder that `r` cannot name. We can blame that
741                 // edge.
742                 self.find_constraint_paths_between_regions(fr1, |r| {
743                     self.constraint_sccs.scc(fr1) == self.constraint_sccs.scc(r)
744                         && self.cannot_name_placeholder(r, fr1)
745                 })
746             })
747             .map(|(_path, r)| r)
748             .unwrap()
749     }
750
751     // Finds a good span to blame for the fact that `fr1` outlives `fr2`.
752     crate fn find_outlives_blame_span(
753         &self,
754         body: &Body<'tcx>,
755         fr1: RegionVid,
756         fr2: RegionVid,
757     ) -> (ConstraintCategory, Span) {
758         let (category, _, span) = self.best_blame_constraint(
759             body,
760             fr1,
761             |r| self.provides_universal_region(r, fr1, fr2),
762         );
763         (category, span)
764     }
765
766     fn retrieve_closure_constraint_info(
767         &self,
768         body: &Body<'tcx>,
769         constraint: &OutlivesConstraint,
770     ) -> (ConstraintCategory, bool, Span) {
771         let loc = match constraint.locations {
772             Locations::All(span) => return (constraint.category, false, span),
773             Locations::Single(loc) => loc,
774         };
775
776         let opt_span_category =
777             self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub));
778         opt_span_category
779             .map(|&(category, span)| (category, true, span))
780             .unwrap_or((constraint.category, false, body.source_info(loc).span))
781     }
782
783     /// Returns `true` if a closure is inferred to be an `FnMut` closure.
784     crate fn is_closure_fn_mut(&self, infcx: &InferCtxt<'_, 'tcx>, fr: RegionVid) -> bool {
785         if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) {
786             if let ty::BoundRegion::BrEnv = free_region.bound_region {
787                 if let DefiningTy::Closure(def_id, substs) = self.universal_regions.defining_ty {
788                     let closure_kind_ty = substs.closure_kind_ty(def_id, infcx.tcx);
789                     return Some(ty::ClosureKind::FnMut) == closure_kind_ty.to_opt_closure_kind();
790                 }
791             }
792         }
793
794         false
795     }
796
797     /// If `r2` represents a placeholder region, then this returns
798     /// `true` if `r1` cannot name that placeholder in its
799     /// value; otherwise, returns `false`.
800     fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool {
801         debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2);
802
803         match self.definitions[r2].origin {
804             NLLRegionVariableOrigin::Placeholder(placeholder) => {
805                 let universe1 = self.definitions[r1].universe;
806                 debug!(
807                     "cannot_name_value_of: universe1={:?} placeholder={:?}",
808                     universe1, placeholder
809                 );
810                 universe1.cannot_name(placeholder.universe)
811             }
812
813             NLLRegionVariableOrigin::FreeRegion | NLLRegionVariableOrigin::Existential => false,
814         }
815     }
816 }