]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/diagnostics/region_name.rs
Rollup merge of #71756 - carstenandrich:master, r=dtolnay
[rust.git] / src / librustc_mir / borrow_check / diagnostics / region_name.rs
1 use std::fmt::{self, Display};
2
3 use rustc_errors::DiagnosticBuilder;
4 use rustc_hir as hir;
5 use rustc_hir::def::{DefKind, Res};
6 use rustc_middle::ty::print::RegionHighlightMode;
7 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
8 use rustc_middle::ty::{self, RegionVid, Ty};
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     /// ```text
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.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
241                     let def_ty = self.regioncx.universal_regions().defining_ty;
242
243                     if let DefiningTy::Closure(_, substs) = def_ty {
244                         let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) =
245                             tcx.hir().expect_expr(mir_hir_id).kind
246                         {
247                             span
248                         } else {
249                             bug!("Closure is not defined by a closure expr");
250                         };
251                         let region_name = self.synthesize_region_name();
252
253                         let closure_kind_ty = substs.as_closure().kind_ty();
254                         let note = match closure_kind_ty.to_opt_closure_kind() {
255                             Some(ty::ClosureKind::Fn) => {
256                                 "closure implements `Fn`, so references to captured variables \
257                                  can't escape the closure"
258                             }
259                             Some(ty::ClosureKind::FnMut) => {
260                                 "closure implements `FnMut`, so references to captured variables \
261                                  can't escape the closure"
262                             }
263                             Some(ty::ClosureKind::FnOnce) => {
264                                 bug!("BrEnv in a `FnOnce` closure");
265                             }
266                             None => bug!("Closure kind not inferred in borrow check"),
267                         };
268
269                         Some(RegionName {
270                             name: region_name,
271                             source: RegionNameSource::SynthesizedFreeEnvRegion(
272                                 args_span,
273                                 note.to_string(),
274                             ),
275                         })
276                     } else {
277                         // Can't have BrEnv in functions, constants or generators.
278                         bug!("BrEnv outside of closure.");
279                     }
280                 }
281
282                 ty::BoundRegion::BrAnon(_) => None,
283             },
284
285             ty::ReLateBound(..)
286             | ty::ReVar(..)
287             | ty::RePlaceholder(..)
288             | ty::ReEmpty(_)
289             | ty::ReErased => None,
290         }
291     }
292
293     /// Finds an argument that contains `fr` and label it with a fully
294     /// elaborated type, returning something like `'1`. Result looks
295     /// like:
296     ///
297     /// ```text
298     ///  | fn foo(x: &u32) { .. }
299     ///           ------- fully elaborated type of `x` is `&'1 u32`
300     /// ```
301     fn give_name_if_anonymous_region_appears_in_arguments(
302         &self,
303         fr: RegionVid,
304     ) -> Option<RegionName> {
305         let implicit_inputs = self.regioncx.universal_regions().defining_ty.implicit_inputs();
306         let argument_index = self.regioncx.get_argument_index_for_region(self.infcx.tcx, fr)?;
307
308         let arg_ty = self.regioncx.universal_regions().unnormalized_input_tys
309             [implicit_inputs + argument_index];
310         if let Some(region_name) =
311             self.give_name_if_we_can_match_hir_ty_from_argument(fr, arg_ty, argument_index)
312         {
313             return Some(region_name);
314         }
315
316         self.give_name_if_we_cannot_match_hir_ty(fr, arg_ty)
317     }
318
319     fn give_name_if_we_can_match_hir_ty_from_argument(
320         &self,
321         needle_fr: RegionVid,
322         argument_ty: Ty<'tcx>,
323         argument_index: usize,
324     ) -> Option<RegionName> {
325         let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
326         let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
327         let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?;
328         match argument_hir_ty.kind {
329             // This indicates a variable with no type annotation, like
330             // `|x|`... in that case, we can't highlight the type but
331             // must highlight the variable.
332             // NOTE(eddyb) this is handled in/by the sole caller
333             // (`give_name_if_anonymous_region_appears_in_arguments`).
334             hir::TyKind::Infer => None,
335
336             _ => self.give_name_if_we_can_match_hir_ty(needle_fr, argument_ty, argument_hir_ty),
337         }
338     }
339
340     /// Attempts to highlight the specific part of a type in an argument
341     /// that has no type annotation.
342     /// For example, we might produce an annotation like this:
343     ///
344     /// ```text
345     ///  |     foo(|a, b| b)
346     ///  |          -  -
347     ///  |          |  |
348     ///  |          |  has type `&'1 u32`
349     ///  |          has type `&'2 u32`
350     /// ```
351     fn give_name_if_we_cannot_match_hir_ty(
352         &self,
353         needle_fr: RegionVid,
354         argument_ty: Ty<'tcx>,
355     ) -> Option<RegionName> {
356         let counter = *self.next_region_name.try_borrow().unwrap();
357         let mut highlight = RegionHighlightMode::default();
358         highlight.highlighting_region_vid(needle_fr, counter);
359         let type_name = self.infcx.extract_type_name(&argument_ty, Some(highlight)).0;
360
361         debug!(
362             "give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
363             type_name, needle_fr
364         );
365         let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() {
366             // Only add a label if we can confirm that a region was labelled.
367             let argument_index =
368                 self.regioncx.get_argument_index_for_region(self.infcx.tcx, needle_fr)?;
369             let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
370                 &self.body,
371                 &self.local_names,
372                 argument_index,
373             );
374
375             Some(RegionName {
376                 // This counter value will already have been used, so this function will increment
377                 // it so the next value will be used next and return the region name that would
378                 // have been used.
379                 name: self.synthesize_region_name(),
380                 source: RegionNameSource::CannotMatchHirTy(span, type_name),
381             })
382         } else {
383             None
384         };
385
386         assigned_region_name
387     }
388
389     /// Attempts to highlight the specific part of a type annotation
390     /// that contains the anonymous reference we want to give a name
391     /// to. For example, we might produce an annotation like this:
392     ///
393     /// ```text
394     ///  | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item = &T>> {
395     ///  |                - let's call the lifetime of this reference `'1`
396     /// ```
397     ///
398     /// the way this works is that we match up `argument_ty`, which is
399     /// a `Ty<'tcx>` (the internal form of the type) with
400     /// `argument_hir_ty`, a `hir::Ty` (the syntax of the type
401     /// annotation). We are descending through the types stepwise,
402     /// looking in to find the region `needle_fr` in the internal
403     /// type. Once we find that, we can use the span of the `hir::Ty`
404     /// to add the highlight.
405     ///
406     /// This is a somewhat imperfect process, so along the way we also
407     /// keep track of the **closest** type we've found. If we fail to
408     /// find the exact `&` or `'_` to highlight, then we may fall back
409     /// to highlighting that closest type instead.
410     fn give_name_if_we_can_match_hir_ty(
411         &self,
412         needle_fr: RegionVid,
413         argument_ty: Ty<'tcx>,
414         argument_hir_ty: &hir::Ty<'_>,
415     ) -> Option<RegionName> {
416         let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> =
417             &mut vec![(argument_ty, argument_hir_ty)];
418
419         while let Some((ty, hir_ty)) = search_stack.pop() {
420             match (&ty.kind, &hir_ty.kind) {
421                 // Check if the `argument_ty` is `&'X ..` where `'X`
422                 // is the region we are looking for -- if so, and we have a `&T`
423                 // on the RHS, then we want to highlight the `&` like so:
424                 //
425                 //     &
426                 //     - let's call the lifetime of this reference `'1`
427                 (
428                     ty::Ref(region, referent_ty, _),
429                     hir::TyKind::Rptr(_lifetime, referent_hir_ty),
430                 ) => {
431                     if region.to_region_vid() == needle_fr {
432                         let region_name = self.synthesize_region_name();
433
434                         // Just grab the first character, the `&`.
435                         let source_map = self.infcx.tcx.sess.source_map();
436                         let ampersand_span = source_map.start_point(hir_ty.span);
437
438                         return Some(RegionName {
439                             name: region_name,
440                             source: RegionNameSource::MatchedHirTy(ampersand_span),
441                         });
442                     }
443
444                     // Otherwise, let's descend into the referent types.
445                     search_stack.push((referent_ty, &referent_hir_ty.ty));
446                 }
447
448                 // Match up something like `Foo<'1>`
449                 (
450                     ty::Adt(_adt_def, substs),
451                     hir::TyKind::Path(hir::QPath::Resolved(None, path)),
452                 ) => {
453                     match path.res {
454                         // Type parameters of the type alias have no reason to
455                         // be the same as those of the ADT.
456                         // FIXME: We should be able to do something similar to
457                         // match_adt_and_segment in this case.
458                         Res::Def(DefKind::TyAlias, _) => (),
459                         _ => {
460                             if let Some(last_segment) = path.segments.last() {
461                                 if let Some(name) = self.match_adt_and_segment(
462                                     substs,
463                                     needle_fr,
464                                     last_segment,
465                                     search_stack,
466                                 ) {
467                                     return Some(name);
468                                 }
469                             }
470                         }
471                     }
472                 }
473
474                 // The following cases don't have lifetimes, so we
475                 // just worry about trying to match up the rustc type
476                 // with the HIR types:
477                 (ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => {
478                     search_stack.extend(elem_tys.iter().map(|k| k.expect_ty()).zip(*elem_hir_tys));
479                 }
480
481                 (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty))
482                 | (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => {
483                     search_stack.push((elem_ty, elem_hir_ty));
484                 }
485
486                 (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => {
487                     search_stack.push((mut_ty.ty, &mut_hir_ty.ty));
488                 }
489
490                 _ => {
491                     // FIXME there are other cases that we could trace
492                 }
493             }
494         }
495
496         None
497     }
498
499     /// We've found an enum/struct/union type with the substitutions
500     /// `substs` and -- in the HIR -- a path type with the final
501     /// segment `last_segment`. Try to find a `'_` to highlight in
502     /// the generic args (or, if not, to produce new zipped pairs of
503     /// types+hir to search through).
504     fn match_adt_and_segment<'hir>(
505         &self,
506         substs: SubstsRef<'tcx>,
507         needle_fr: RegionVid,
508         last_segment: &'hir hir::PathSegment<'hir>,
509         search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>,
510     ) -> Option<RegionName> {
511         // Did the user give explicit arguments? (e.g., `Foo<..>`)
512         let args = last_segment.args.as_ref()?;
513         let lifetime =
514             self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
515         match lifetime.name {
516             hir::LifetimeName::Param(_)
517             | hir::LifetimeName::Error
518             | hir::LifetimeName::Static
519             | hir::LifetimeName::Underscore => {
520                 let region_name = self.synthesize_region_name();
521                 let ampersand_span = lifetime.span;
522                 Some(RegionName {
523                     name: region_name,
524                     source: RegionNameSource::MatchedAdtAndSegment(ampersand_span),
525                 })
526             }
527
528             hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
529                 // In this case, the user left off the lifetime; so
530                 // they wrote something like:
531                 //
532                 // ```
533                 // x: Foo<T>
534                 // ```
535                 //
536                 // where the fully elaborated form is `Foo<'_, '1,
537                 // T>`. We don't consider this a match; instead we let
538                 // the "fully elaborated" type fallback above handle
539                 // it.
540                 None
541             }
542         }
543     }
544
545     /// We've found an enum/struct/union type with the substitutions
546     /// `substs` and -- in the HIR -- a path with the generic
547     /// arguments `args`. If `needle_fr` appears in the args, return
548     /// the `hir::Lifetime` that corresponds to it. If not, push onto
549     /// `search_stack` the types+hir to search through.
550     fn try_match_adt_and_generic_args<'hir>(
551         &self,
552         substs: SubstsRef<'tcx>,
553         needle_fr: RegionVid,
554         args: &'hir hir::GenericArgs<'hir>,
555         search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>,
556     ) -> Option<&'hir hir::Lifetime> {
557         for (kind, hir_arg) in substs.iter().zip(args.args) {
558             match (kind.unpack(), hir_arg) {
559                 (GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => {
560                     if r.to_region_vid() == needle_fr {
561                         return Some(lt);
562                     }
563                 }
564
565                 (GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => {
566                     search_stack.push((ty, hir_ty));
567                 }
568
569                 (GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => {
570                     // Lifetimes cannot be found in consts, so we don't need
571                     // to search anything here.
572                 }
573
574                 (
575                     GenericArgKind::Lifetime(_)
576                     | GenericArgKind::Type(_)
577                     | GenericArgKind::Const(_),
578                     _,
579                 ) => {
580                     // I *think* that HIR lowering should ensure this
581                     // doesn't happen, even in erroneous
582                     // programs. Else we should use delay-span-bug.
583                     span_bug!(
584                         hir_arg.span(),
585                         "unmatched subst and hir arg: found {:?} vs {:?}",
586                         kind,
587                         hir_arg,
588                     );
589                 }
590             }
591         }
592
593         None
594     }
595
596     /// Finds a closure upvar that contains `fr` and label it with a
597     /// fully elaborated type, returning something like `'1`. Result
598     /// looks like:
599     ///
600     /// ```text
601     ///  | let x = Some(&22);
602     ///        - fully elaborated type of `x` is `Option<&'1 u32>`
603     /// ```
604     fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
605         let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
606         let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
607             self.infcx.tcx,
608             &self.upvars,
609             upvar_index,
610         );
611         let region_name = self.synthesize_region_name();
612
613         Some(RegionName {
614             name: region_name,
615             source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name.to_string()),
616         })
617     }
618
619     /// Checks for arguments appearing in the (closure) return type. It
620     /// must be a closure since, in a free fn, such an argument would
621     /// have to either also appear in an argument (if using elision)
622     /// or be early bound (named, not in argument).
623     fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> {
624         let tcx = self.infcx.tcx;
625
626         let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
627         debug!("give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty);
628         if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) {
629             return None;
630         }
631
632         let mut highlight = RegionHighlightMode::default();
633         highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
634         let type_name = self.infcx.extract_type_name(&return_ty, Some(highlight)).0;
635
636         let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id);
637
638         let (return_span, mir_description) = match tcx.hir().get(mir_hir_id) {
639             hir::Node::Expr(hir::Expr {
640                 kind: hir::ExprKind::Closure(_, return_ty, _, span, gen_move),
641                 ..
642             }) => (
643                 match return_ty.output {
644                     hir::FnRetTy::DefaultReturn(_) => tcx.sess.source_map().end_point(*span),
645                     hir::FnRetTy::Return(_) => return_ty.output.span(),
646                 },
647                 if gen_move.is_some() { " of generator" } else { " of closure" },
648             ),
649             hir::Node::ImplItem(hir::ImplItem {
650                 kind: hir::ImplItemKind::Fn(method_sig, _),
651                 ..
652             }) => (method_sig.decl.output.span(), ""),
653             _ => (self.body.span, ""),
654         };
655
656         Some(RegionName {
657             // This counter value will already have been used, so this function will increment it
658             // so the next value will be used next and return the region name that would have been
659             // used.
660             name: self.synthesize_region_name(),
661             source: RegionNameSource::AnonRegionFromOutput(
662                 return_span,
663                 mir_description.to_string(),
664                 type_name,
665             ),
666         })
667     }
668
669     fn give_name_if_anonymous_region_appears_in_yield_ty(
670         &self,
671         fr: RegionVid,
672     ) -> Option<RegionName> {
673         // Note: generators from `async fn` yield `()`, so we don't have to
674         // worry about them here.
675         let yield_ty = self.regioncx.universal_regions().yield_ty?;
676         debug!("give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}", yield_ty,);
677
678         let tcx = self.infcx.tcx;
679
680         if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) {
681             return None;
682         }
683
684         let mut highlight = RegionHighlightMode::default();
685         highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
686         let type_name = self.infcx.extract_type_name(&yield_ty, Some(highlight)).0;
687
688         let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id);
689
690         let yield_span = match tcx.hir().get(mir_hir_id) {
691             hir::Node::Expr(hir::Expr {
692                 kind: hir::ExprKind::Closure(_, _, _, span, _), ..
693             }) => (tcx.sess.source_map().end_point(*span)),
694             _ => self.body.span,
695         };
696
697         debug!(
698             "give_name_if_anonymous_region_appears_in_yield_ty: \
699              type_name = {:?}, yield_span = {:?}",
700             yield_span, type_name,
701         );
702
703         Some(RegionName {
704             name: self.synthesize_region_name(),
705             source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
706         })
707     }
708 }