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