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