]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/diagnostics/region_name.rs
Auto merge of #69590 - Dylan-DPC:rollup-i3z0sic, r=Dylan-DPC
[rust.git] / src / librustc_mir / borrow_check / diagnostics / region_name.rs
1 use std::fmt::{self, Display};
2
3 use rustc::ty::print::RegionHighlightMode;
4 use rustc::ty::subst::{GenericArgKind, SubstsRef};
5 use rustc::ty::{self, RegionVid, Ty};
6 use rustc_errors::DiagnosticBuilder;
7 use rustc_hir as hir;
8 use rustc_hir::def::{DefKind, Res};
9 use rustc_span::symbol::kw;
10 use rustc_span::{symbol::Symbol, Span, DUMMY_SP};
11
12 use crate::borrow_check::{nll::ToRegionVid, universal_regions::DefiningTy, MirBorrowckCtxt};
13
14 /// A name for a particular region used in emitting diagnostics. This name could be a generated
15 /// name like `'1`, a name used by the user like `'a`, or a name like `'static`.
16 #[derive(Debug, Clone)]
17 crate struct RegionName {
18     /// The name of the region (interned).
19     crate name: Symbol,
20     /// Where the region comes from.
21     crate source: RegionNameSource,
22 }
23
24 /// Denotes the source of a region that is named by a `RegionName`. For example, a free region that
25 /// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`.
26 /// This helps to print the right kinds of diagnostics.
27 #[derive(Debug, Clone)]
28 crate enum RegionNameSource {
29     /// A bound (not free) region that was substituted at the def site (not an HRTB).
30     NamedEarlyBoundRegion(Span),
31     /// A free region that the user has a name (`'a`) for.
32     NamedFreeRegion(Span),
33     /// The `'static` region.
34     Static,
35     /// The free region corresponding to the environment of a closure.
36     SynthesizedFreeEnvRegion(Span, String),
37     /// The region name corresponds to a region where the type annotation is completely missing
38     /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
39     CannotMatchHirTy(Span, String),
40     /// The region name corresponds a reference that was found by traversing the type in the HIR.
41     MatchedHirTy(Span),
42     /// A region name from the generics list of a struct/enum/union.
43     MatchedAdtAndSegment(Span),
44     /// The region corresponding to a closure upvar.
45     AnonRegionFromUpvar(Span, String),
46     /// The region corresponding to the return type of a closure.
47     AnonRegionFromOutput(Span, String, String),
48     /// The region from a type yielded by a generator.
49     AnonRegionFromYieldTy(Span, String),
50     /// An anonymous region from an async fn.
51     AnonRegionFromAsyncFn(Span),
52 }
53
54 impl RegionName {
55     crate fn was_named(&self) -> bool {
56         match self.source {
57             RegionNameSource::NamedEarlyBoundRegion(..)
58             | RegionNameSource::NamedFreeRegion(..)
59             | RegionNameSource::Static => true,
60             RegionNameSource::SynthesizedFreeEnvRegion(..)
61             | RegionNameSource::CannotMatchHirTy(..)
62             | RegionNameSource::MatchedHirTy(..)
63             | RegionNameSource::MatchedAdtAndSegment(..)
64             | RegionNameSource::AnonRegionFromUpvar(..)
65             | RegionNameSource::AnonRegionFromOutput(..)
66             | RegionNameSource::AnonRegionFromYieldTy(..)
67             | RegionNameSource::AnonRegionFromAsyncFn(..) => false,
68         }
69     }
70
71     crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
72         match &self.source {
73             RegionNameSource::NamedFreeRegion(span)
74             | RegionNameSource::NamedEarlyBoundRegion(span) => {
75                 diag.span_label(*span, format!("lifetime `{}` defined here", self));
76             }
77             RegionNameSource::SynthesizedFreeEnvRegion(span, note) => {
78                 diag.span_label(
79                     *span,
80                     format!("lifetime `{}` represents this closure's body", self),
81                 );
82                 diag.note(&note);
83             }
84             RegionNameSource::CannotMatchHirTy(span, type_name) => {
85                 diag.span_label(*span, format!("has type `{}`", type_name));
86             }
87             RegionNameSource::MatchedHirTy(span)
88             | RegionNameSource::AnonRegionFromAsyncFn(span) => {
89                 diag.span_label(
90                     *span,
91                     format!("let's call the lifetime of this reference `{}`", self),
92                 );
93             }
94             RegionNameSource::MatchedAdtAndSegment(span) => {
95                 diag.span_label(*span, format!("let's call this `{}`", self));
96             }
97             RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => {
98                 diag.span_label(
99                     *span,
100                     format!("lifetime `{}` appears in the type of `{}`", self, upvar_name),
101                 );
102             }
103             RegionNameSource::AnonRegionFromOutput(span, mir_description, type_name) => {
104                 diag.span_label(*span, format!("return type{} is {}", mir_description, type_name));
105             }
106             RegionNameSource::AnonRegionFromYieldTy(span, type_name) => {
107                 diag.span_label(*span, format!("yield type is {}", type_name));
108             }
109             RegionNameSource::Static => {}
110         }
111     }
112 }
113
114 impl Display for RegionName {
115     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116         write!(f, "{}", self.name)
117     }
118 }
119
120 impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
121     /// Generate a synthetic region named `'N`, where `N` is the next value of the counter. Then,
122     /// increment the counter.
123     ///
124     /// This is _not_ idempotent. Call `give_region_a_name` when possible.
125     fn synthesize_region_name(&self) -> Symbol {
126         let c = self.next_region_name.replace_with(|counter| *counter + 1);
127         Symbol::intern(&format!("'{:?}", c))
128     }
129
130     /// Maps from an internal MIR region vid to something that we can
131     /// report to the user. In some cases, the region vids will map
132     /// directly to lifetimes that the user has a name for (e.g.,
133     /// `'static`). But frequently they will not, in which case we
134     /// have to find some way to identify the lifetime to the user. To
135     /// that end, this function takes a "diagnostic" so that it can
136     /// create auxiliary notes as needed.
137     ///
138     /// The names are memoized, so this is both cheap to recompute and idempotent.
139     ///
140     /// Example (function arguments):
141     ///
142     /// Suppose we are trying to give a name to the lifetime of the
143     /// reference `x`:
144     ///
145     /// ```
146     /// fn foo(x: &u32) { .. }
147     /// ```
148     ///
149     /// This function would create a label like this:
150     ///
151     /// ```
152     ///  | fn foo(x: &u32) { .. }
153     ///           ------- fully elaborated type of `x` is `&'1 u32`
154     /// ```
155     ///
156     /// and then return the name `'1` for us to use.
157     crate fn give_region_a_name(&self, fr: RegionVid) -> Option<RegionName> {
158         debug!(
159             "give_region_a_name(fr={:?}, counter={:?})",
160             fr,
161             self.next_region_name.try_borrow().unwrap()
162         );
163
164         assert!(self.regioncx.universal_regions().is_universal_region(fr));
165
166         if let Some(value) = self.region_names.try_borrow_mut().unwrap().get(&fr) {
167             return Some(value.clone());
168         }
169
170         let value = self
171             .give_name_from_error_region(fr)
172             .or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr))
173             .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr))
174             .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr))
175             .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr));
176
177         if let Some(ref value) = value {
178             self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone());
179         }
180
181         debug!("give_region_a_name: gave name {:?}", value);
182         value
183     }
184
185     /// Checks for the case where `fr` maps to something that the
186     /// *user* has a name for. In that case, we'll be able to map
187     /// `fr` to a `Region<'tcx>`, and that region will be one of
188     /// named variants.
189     fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
190         let error_region = self.to_error_region(fr)?;
191
192         let tcx = self.infcx.tcx;
193
194         debug!("give_region_a_name: error_region = {:?}", error_region);
195         match error_region {
196             ty::ReEarlyBound(ebr) => {
197                 if ebr.has_name() {
198                     let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP);
199                     Some(RegionName {
200                         name: ebr.name,
201                         source: RegionNameSource::NamedEarlyBoundRegion(span),
202                     })
203                 } else {
204                     None
205                 }
206             }
207
208             ty::ReStatic => {
209                 Some(RegionName { name: kw::StaticLifetime, source: RegionNameSource::Static })
210             }
211
212             ty::ReFree(free_region) => match free_region.bound_region {
213                 ty::BoundRegion::BrNamed(region_def_id, name) => {
214                     // Get the span to point to, even if we don't use the name.
215                     let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP);
216                     debug!(
217                         "bound region named: {:?}, is_named: {:?}",
218                         name,
219                         free_region.bound_region.is_named()
220                     );
221
222                     if free_region.bound_region.is_named() {
223                         // A named region that is actually named.
224                         Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) })
225                     } else {
226                         // If we spuriously thought that the region is named, we should let the
227                         // system generate a true name for error messages. Currently this can
228                         // happen if we have an elided name in an async fn for example: the
229                         // compiler will generate a region named `'_`, but reporting such a name is
230                         // not actually useful, so we synthesize a name for it instead.
231                         let name = self.synthesize_region_name();
232                         Some(RegionName {
233                             name,
234                             source: RegionNameSource::AnonRegionFromAsyncFn(span),
235                         })
236                     }
237                 }
238
239                 ty::BoundRegion::BrEnv => {
240                     let mir_hir_id = self
241                         .infcx
242                         .tcx
243                         .hir()
244                         .as_local_hir_id(self.mir_def_id)
245                         .expect("non-local mir");
246                     let def_ty = self.regioncx.universal_regions().defining_ty;
247
248                     if let DefiningTy::Closure(def_id, substs) = def_ty {
249                         let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) =
250                             tcx.hir().expect_expr(mir_hir_id).kind
251                         {
252                             span
253                         } else {
254                             bug!("Closure is not defined by a closure expr");
255                         };
256                         let region_name = self.synthesize_region_name();
257
258                         let closure_kind_ty = substs.as_closure().kind_ty(def_id, tcx);
259                         let note = match closure_kind_ty.to_opt_closure_kind() {
260                             Some(ty::ClosureKind::Fn) => {
261                                 "closure implements `Fn`, so references to captured variables \
262                                  can't escape the closure"
263                             }
264                             Some(ty::ClosureKind::FnMut) => {
265                                 "closure implements `FnMut`, so references to captured variables \
266                                  can't escape the closure"
267                             }
268                             Some(ty::ClosureKind::FnOnce) => {
269                                 bug!("BrEnv in a `FnOnce` closure");
270                             }
271                             None => bug!("Closure kind not inferred in borrow check"),
272                         };
273
274                         Some(RegionName {
275                             name: region_name,
276                             source: RegionNameSource::SynthesizedFreeEnvRegion(
277                                 args_span,
278                                 note.to_string(),
279                             ),
280                         })
281                     } else {
282                         // Can't have BrEnv in functions, constants or generators.
283                         bug!("BrEnv outside of closure.");
284                     }
285                 }
286
287                 ty::BoundRegion::BrAnon(_) => None,
288             },
289
290             ty::ReLateBound(..)
291             | ty::ReScope(..)
292             | ty::ReVar(..)
293             | ty::RePlaceholder(..)
294             | ty::ReEmpty(_)
295             | ty::ReErased
296             | ty::ReClosureBound(..) => None,
297         }
298     }
299
300     /// Finds an argument that contains `fr` and label it with a fully
301     /// elaborated type, returning something like `'1`. Result looks
302     /// like:
303     ///
304     /// ```
305     ///  | fn foo(x: &u32) { .. }
306     ///           ------- fully elaborated type of `x` is `&'1 u32`
307     /// ```
308     fn give_name_if_anonymous_region_appears_in_arguments(
309         &self,
310         fr: RegionVid,
311     ) -> Option<RegionName> {
312         let implicit_inputs = self.regioncx.universal_regions().defining_ty.implicit_inputs();
313         let argument_index = self.regioncx.get_argument_index_for_region(self.infcx.tcx, fr)?;
314
315         let arg_ty = self.regioncx.universal_regions().unnormalized_input_tys
316             [implicit_inputs + argument_index];
317         if let Some(region_name) =
318             self.give_name_if_we_can_match_hir_ty_from_argument(fr, arg_ty, argument_index)
319         {
320             return Some(region_name);
321         }
322
323         self.give_name_if_we_cannot_match_hir_ty(fr, arg_ty)
324     }
325
326     fn give_name_if_we_can_match_hir_ty_from_argument(
327         &self,
328         needle_fr: RegionVid,
329         argument_ty: Ty<'tcx>,
330         argument_index: usize,
331     ) -> Option<RegionName> {
332         let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id)?;
333         let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
334         let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?;
335         match argument_hir_ty.kind {
336             // This indicates a variable with no type annotation, like
337             // `|x|`... in that case, we can't highlight the type but
338             // must highlight the variable.
339             // NOTE(eddyb) this is handled in/by the sole caller
340             // (`give_name_if_anonymous_region_appears_in_arguments`).
341             hir::TyKind::Infer => None,
342
343             _ => self.give_name_if_we_can_match_hir_ty(needle_fr, argument_ty, argument_hir_ty),
344         }
345     }
346
347     /// Attempts to highlight the specific part of a type in an argument
348     /// that has no type annotation.
349     /// For example, we might produce an annotation like this:
350     ///
351     /// ```
352     ///  |     foo(|a, b| b)
353     ///  |          -  -
354     ///  |          |  |
355     ///  |          |  has type `&'1 u32`
356     ///  |          has type `&'2 u32`
357     /// ```
358     fn give_name_if_we_cannot_match_hir_ty(
359         &self,
360         needle_fr: RegionVid,
361         argument_ty: Ty<'tcx>,
362     ) -> Option<RegionName> {
363         let counter = *self.next_region_name.try_borrow().unwrap();
364         let mut highlight = RegionHighlightMode::default();
365         highlight.highlighting_region_vid(needle_fr, counter);
366         let type_name = self.infcx.extract_type_name(&argument_ty, Some(highlight)).0;
367
368         debug!(
369             "give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
370             type_name, needle_fr
371         );
372         let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() {
373             // Only add a label if we can confirm that a region was labelled.
374             let argument_index =
375                 self.regioncx.get_argument_index_for_region(self.infcx.tcx, needle_fr)?;
376             let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
377                 &self.body,
378                 &self.local_names,
379                 argument_index,
380             );
381
382             Some(RegionName {
383                 // This counter value will already have been used, so this function will increment
384                 // it so the next value will be used next and return the region name that would
385                 // have been used.
386                 name: self.synthesize_region_name(),
387                 source: RegionNameSource::CannotMatchHirTy(span, type_name),
388             })
389         } else {
390             None
391         };
392
393         assigned_region_name
394     }
395
396     /// Attempts to highlight the specific part of a type annotation
397     /// that contains the anonymous reference we want to give a name
398     /// to. For example, we might produce an annotation like this:
399     ///
400     /// ```
401     ///  | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item = &T>> {
402     ///  |                - let's call the lifetime of this reference `'1`
403     /// ```
404     ///
405     /// the way this works is that we match up `argument_ty`, which is
406     /// a `Ty<'tcx>` (the internal form of the type) with
407     /// `argument_hir_ty`, a `hir::Ty` (the syntax of the type
408     /// annotation). We are descending through the types stepwise,
409     /// looking in to find the region `needle_fr` in the internal
410     /// type. Once we find that, we can use the span of the `hir::Ty`
411     /// to add the highlight.
412     ///
413     /// This is a somewhat imperfect process, so along the way we also
414     /// keep track of the **closest** type we've found. If we fail to
415     /// find the exact `&` or `'_` to highlight, then we may fall back
416     /// to highlighting that closest type instead.
417     fn give_name_if_we_can_match_hir_ty(
418         &self,
419         needle_fr: RegionVid,
420         argument_ty: Ty<'tcx>,
421         argument_hir_ty: &hir::Ty<'_>,
422     ) -> Option<RegionName> {
423         let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> =
424             &mut vec![(argument_ty, argument_hir_ty)];
425
426         while let Some((ty, hir_ty)) = search_stack.pop() {
427             match (&ty.kind, &hir_ty.kind) {
428                 // Check if the `argument_ty` is `&'X ..` where `'X`
429                 // is the region we are looking for -- if so, and we have a `&T`
430                 // on the RHS, then we want to highlight the `&` like so:
431                 //
432                 //     &
433                 //     - let's call the lifetime of this reference `'1`
434                 (
435                     ty::Ref(region, referent_ty, _),
436                     hir::TyKind::Rptr(_lifetime, referent_hir_ty),
437                 ) => {
438                     if region.to_region_vid() == needle_fr {
439                         let region_name = self.synthesize_region_name();
440
441                         // Just grab the first character, the `&`.
442                         let source_map = self.infcx.tcx.sess.source_map();
443                         let ampersand_span = source_map.start_point(hir_ty.span);
444
445                         return Some(RegionName {
446                             name: region_name,
447                             source: RegionNameSource::MatchedHirTy(ampersand_span),
448                         });
449                     }
450
451                     // Otherwise, let's descend into the referent types.
452                     search_stack.push((referent_ty, &referent_hir_ty.ty));
453                 }
454
455                 // Match up something like `Foo<'1>`
456                 (
457                     ty::Adt(_adt_def, substs),
458                     hir::TyKind::Path(hir::QPath::Resolved(None, path)),
459                 ) => {
460                     match path.res {
461                         // Type parameters of the type alias have no reason to
462                         // be the same as those of the ADT.
463                         // FIXME: We should be able to do something similar to
464                         // match_adt_and_segment in this case.
465                         Res::Def(DefKind::TyAlias, _) => (),
466                         _ => {
467                             if let Some(last_segment) = path.segments.last() {
468                                 if let Some(name) = self.match_adt_and_segment(
469                                     substs,
470                                     needle_fr,
471                                     last_segment,
472                                     search_stack,
473                                 ) {
474                                     return Some(name);
475                                 }
476                             }
477                         }
478                     }
479                 }
480
481                 // The following cases don't have lifetimes, so we
482                 // just worry about trying to match up the rustc type
483                 // with the HIR types:
484                 (ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => {
485                     search_stack.extend(elem_tys.iter().map(|k| k.expect_ty()).zip(*elem_hir_tys));
486                 }
487
488                 (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty))
489                 | (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => {
490                     search_stack.push((elem_ty, elem_hir_ty));
491                 }
492
493                 (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => {
494                     search_stack.push((mut_ty.ty, &mut_hir_ty.ty));
495                 }
496
497                 _ => {
498                     // FIXME there are other cases that we could trace
499                 }
500             }
501         }
502
503         return None;
504     }
505
506     /// We've found an enum/struct/union type with the substitutions
507     /// `substs` and -- in the HIR -- a path type with the final
508     /// segment `last_segment`. Try to find a `'_` to highlight in
509     /// the generic args (or, if not, to produce new zipped pairs of
510     /// types+hir to search through).
511     fn match_adt_and_segment<'hir>(
512         &self,
513         substs: SubstsRef<'tcx>,
514         needle_fr: RegionVid,
515         last_segment: &'hir hir::PathSegment<'hir>,
516         search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>,
517     ) -> Option<RegionName> {
518         // Did the user give explicit arguments? (e.g., `Foo<..>`)
519         let args = last_segment.args.as_ref()?;
520         let lifetime =
521             self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
522         match lifetime.name {
523             hir::LifetimeName::Param(_)
524             | hir::LifetimeName::Error
525             | hir::LifetimeName::Static
526             | hir::LifetimeName::Underscore => {
527                 let region_name = self.synthesize_region_name();
528                 let ampersand_span = lifetime.span;
529                 Some(RegionName {
530                     name: region_name,
531                     source: RegionNameSource::MatchedAdtAndSegment(ampersand_span),
532                 })
533             }
534
535             hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
536                 // In this case, the user left off the lifetime; so
537                 // they wrote something like:
538                 //
539                 // ```
540                 // x: Foo<T>
541                 // ```
542                 //
543                 // where the fully elaborated form is `Foo<'_, '1,
544                 // T>`. We don't consider this a match; instead we let
545                 // the "fully elaborated" type fallback above handle
546                 // it.
547                 None
548             }
549         }
550     }
551
552     /// We've found an enum/struct/union type with the substitutions
553     /// `substs` and -- in the HIR -- a path with the generic
554     /// arguments `args`. If `needle_fr` appears in the args, return
555     /// the `hir::Lifetime` that corresponds to it. If not, push onto
556     /// `search_stack` the types+hir to search through.
557     fn try_match_adt_and_generic_args<'hir>(
558         &self,
559         substs: SubstsRef<'tcx>,
560         needle_fr: RegionVid,
561         args: &'hir hir::GenericArgs<'hir>,
562         search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>,
563     ) -> Option<&'hir hir::Lifetime> {
564         for (kind, hir_arg) in substs.iter().zip(args.args) {
565             match (kind.unpack(), hir_arg) {
566                 (GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => {
567                     if r.to_region_vid() == needle_fr {
568                         return Some(lt);
569                     }
570                 }
571
572                 (GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => {
573                     search_stack.push((ty, hir_ty));
574                 }
575
576                 (GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => {
577                     // Lifetimes cannot be found in consts, so we don't need
578                     // to search anything here.
579                 }
580
581                 (GenericArgKind::Lifetime(_), _)
582                 | (GenericArgKind::Type(_), _)
583                 | (GenericArgKind::Const(_), _) => {
584                     // I *think* that HIR lowering should ensure this
585                     // doesn't happen, even in erroneous
586                     // programs. Else we should use delay-span-bug.
587                     span_bug!(
588                         hir_arg.span(),
589                         "unmatched subst and hir arg: found {:?} vs {:?}",
590                         kind,
591                         hir_arg,
592                     );
593                 }
594             }
595         }
596
597         None
598     }
599
600     /// Finds a closure upvar that contains `fr` and label it with a
601     /// fully elaborated type, returning something like `'1`. Result
602     /// looks like:
603     ///
604     /// ```
605     ///  | let x = Some(&22);
606     ///        - fully elaborated type of `x` is `Option<&'1 u32>`
607     /// ```
608     fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
609         let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
610         let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
611             self.infcx.tcx,
612             &self.upvars,
613             upvar_index,
614         );
615         let region_name = self.synthesize_region_name();
616
617         Some(RegionName {
618             name: region_name,
619             source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name.to_string()),
620         })
621     }
622
623     /// Checks for arguments appearing in the (closure) return type. It
624     /// must be a closure since, in a free fn, such an argument would
625     /// have to either also appear in an argument (if using elision)
626     /// or be early bound (named, not in argument).
627     fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> {
628         let tcx = self.infcx.tcx;
629
630         let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
631         debug!("give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty);
632         if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) {
633             return None;
634         }
635
636         let mut highlight = RegionHighlightMode::default();
637         highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
638         let type_name = self.infcx.extract_type_name(&return_ty, Some(highlight)).0;
639
640         let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id).expect("non-local mir");
641
642         let (return_span, mir_description) = match tcx.hir().get(mir_hir_id) {
643             hir::Node::Expr(hir::Expr {
644                 kind: hir::ExprKind::Closure(_, return_ty, _, span, gen_move),
645                 ..
646             }) => (
647                 match return_ty.output {
648                     hir::FnRetTy::DefaultReturn(_) => tcx.sess.source_map().end_point(*span),
649                     hir::FnRetTy::Return(_) => return_ty.output.span(),
650                 },
651                 if gen_move.is_some() { " of generator" } else { " of closure" },
652             ),
653             hir::Node::ImplItem(hir::ImplItem {
654                 kind: hir::ImplItemKind::Method(method_sig, _),
655                 ..
656             }) => (method_sig.decl.output.span(), ""),
657             _ => (self.body.span, ""),
658         };
659
660         Some(RegionName {
661             // This counter value will already have been used, so this function will increment it
662             // so the next value will be used next and return the region name that would have been
663             // used.
664             name: self.synthesize_region_name(),
665             source: RegionNameSource::AnonRegionFromOutput(
666                 return_span,
667                 mir_description.to_string(),
668                 type_name,
669             ),
670         })
671     }
672
673     fn give_name_if_anonymous_region_appears_in_yield_ty(
674         &self,
675         fr: RegionVid,
676     ) -> Option<RegionName> {
677         // Note: generators from `async fn` yield `()`, so we don't have to
678         // worry about them here.
679         let yield_ty = self.regioncx.universal_regions().yield_ty?;
680         debug!("give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}", yield_ty,);
681
682         let tcx = self.infcx.tcx;
683
684         if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) {
685             return None;
686         }
687
688         let mut highlight = RegionHighlightMode::default();
689         highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
690         let type_name = self.infcx.extract_type_name(&yield_ty, Some(highlight)).0;
691
692         let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id).expect("non-local mir");
693
694         let yield_span = match tcx.hir().get(mir_hir_id) {
695             hir::Node::Expr(hir::Expr {
696                 kind: hir::ExprKind::Closure(_, _, _, span, _), ..
697             }) => (tcx.sess.source_map().end_point(*span)),
698             _ => self.body.span,
699         };
700
701         debug!(
702             "give_name_if_anonymous_region_appears_in_yield_ty: \
703              type_name = {:?}, yield_span = {:?}",
704             yield_span, type_name,
705         );
706
707         Some(RegionName {
708             name: self.synthesize_region_name(),
709             source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
710         })
711     }
712 }