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