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