]>
Commit | Line | Data |
---|---|---|
0bf4aa26 | 1 | use std::fmt::{self, Display}; |
cdc7bbd5 | 2 | use std::iter; |
e1599b0c | 3 | |
5e7ed085 | 4 | use rustc_errors::Diagnostic; |
dfeec247 XL |
5 | use rustc_hir as hir; |
6 | use rustc_hir::def::{DefKind, Res}; | |
ba9703b0 XL |
7 | use rustc_middle::ty::print::RegionHighlightMode; |
8 | use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; | |
923072b8 | 9 | use rustc_middle::ty::{self, DefIdTree, RegionVid, Ty}; |
29967ef6 XL |
10 | use rustc_span::symbol::{kw, sym, Ident, Symbol}; |
11 | use rustc_span::{Span, DUMMY_SP}; | |
dfeec247 | 12 | |
c295e0f8 | 13 | use crate::{nll::ToRegionVid, universal_regions::DefiningTy, MirBorrowckCtxt}; |
8faf50e0 | 14 | |
e1599b0c XL |
15 | /// A name for a particular region used in emitting diagnostics. This name could be a generated |
16 | /// name like `'1`, a name used by the user like `'a`, or a name like `'static`. | |
17 | #[derive(Debug, Clone)] | |
923072b8 | 18 | pub(crate) struct RegionName { |
e1599b0c | 19 | /// The name of the region (interned). |
923072b8 | 20 | pub(crate) name: Symbol, |
e1599b0c | 21 | /// Where the region comes from. |
923072b8 | 22 | pub(crate) source: RegionNameSource, |
0bf4aa26 XL |
23 | } |
24 | ||
e1599b0c XL |
25 | /// Denotes the source of a region that is named by a `RegionName`. For example, a free region that |
26 | /// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`. | |
27 | /// This helps to print the right kinds of diagnostics. | |
28 | #[derive(Debug, Clone)] | |
923072b8 | 29 | pub(crate) enum RegionNameSource { |
e1599b0c | 30 | /// A bound (not free) region that was substituted at the def site (not an HRTB). |
0bf4aa26 | 31 | NamedEarlyBoundRegion(Span), |
e1599b0c | 32 | /// A free region that the user has a name (`'a`) for. |
0bf4aa26 | 33 | NamedFreeRegion(Span), |
e1599b0c | 34 | /// The `'static` region. |
0bf4aa26 | 35 | Static, |
e1599b0c | 36 | /// The free region corresponding to the environment of a closure. |
064997fb | 37 | SynthesizedFreeEnvRegion(Span, &'static str), |
3dfed10e XL |
38 | /// The region corresponding to an argument. |
39 | AnonRegionFromArgument(RegionNameHighlight), | |
e1599b0c | 40 | /// The region corresponding to a closure upvar. |
064997fb | 41 | AnonRegionFromUpvar(Span, Symbol), |
e1599b0c | 42 | /// The region corresponding to the return type of a closure. |
064997fb | 43 | AnonRegionFromOutput(RegionNameHighlight, &'static str), |
60c5eb7d | 44 | /// The region from a type yielded by a generator. |
48663c56 | 45 | AnonRegionFromYieldTy(Span, String), |
60c5eb7d XL |
46 | /// An anonymous region from an async fn. |
47 | AnonRegionFromAsyncFn(Span), | |
923072b8 FG |
48 | /// An anonymous region from an impl self type or trait |
49 | AnonRegionFromImplSignature(Span, &'static str), | |
0bf4aa26 XL |
50 | } |
51 | ||
3dfed10e XL |
52 | /// Describes what to highlight to explain to the user that we're giving an anonymous region a |
53 | /// synthesized name, and how to highlight it. | |
54 | #[derive(Debug, Clone)] | |
923072b8 | 55 | pub(crate) enum RegionNameHighlight { |
3dfed10e XL |
56 | /// The anonymous region corresponds to a reference that was found by traversing the type in the HIR. |
57 | MatchedHirTy(Span), | |
58 | /// The anonymous region corresponds to a `'_` in the generics list of a struct/enum/union. | |
59 | MatchedAdtAndSegment(Span), | |
60 | /// The anonymous region corresponds to a region where the type annotation is completely missing | |
61 | /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference. | |
62 | CannotMatchHirTy(Span, String), | |
29967ef6 XL |
63 | /// The anonymous region corresponds to a region where the type annotation is completely missing |
64 | /// from the code, and *even if* we print out the full name of the type, the region name won't | |
65 | /// be included. This currently occurs for opaque types like `impl Future`. | |
66 | Occluded(Span, String), | |
3dfed10e XL |
67 | } |
68 | ||
0bf4aa26 | 69 | impl RegionName { |
923072b8 | 70 | pub(crate) fn was_named(&self) -> bool { |
0bf4aa26 | 71 | match self.source { |
dfeec247 XL |
72 | RegionNameSource::NamedEarlyBoundRegion(..) |
73 | | RegionNameSource::NamedFreeRegion(..) | |
74 | | RegionNameSource::Static => true, | |
75 | RegionNameSource::SynthesizedFreeEnvRegion(..) | |
3dfed10e | 76 | | RegionNameSource::AnonRegionFromArgument(..) |
dfeec247 XL |
77 | | RegionNameSource::AnonRegionFromUpvar(..) |
78 | | RegionNameSource::AnonRegionFromOutput(..) | |
79 | | RegionNameSource::AnonRegionFromYieldTy(..) | |
923072b8 FG |
80 | | RegionNameSource::AnonRegionFromAsyncFn(..) |
81 | | RegionNameSource::AnonRegionFromImplSignature(..) => false, | |
0bf4aa26 XL |
82 | } |
83 | } | |
84 | ||
923072b8 | 85 | pub(crate) fn span(&self) -> Option<Span> { |
3dfed10e XL |
86 | match self.source { |
87 | RegionNameSource::Static => None, | |
88 | RegionNameSource::NamedEarlyBoundRegion(span) | |
89 | | RegionNameSource::NamedFreeRegion(span) | |
90 | | RegionNameSource::SynthesizedFreeEnvRegion(span, _) | |
91 | | RegionNameSource::AnonRegionFromUpvar(span, _) | |
3dfed10e | 92 | | RegionNameSource::AnonRegionFromYieldTy(span, _) |
923072b8 FG |
93 | | RegionNameSource::AnonRegionFromAsyncFn(span) |
94 | | RegionNameSource::AnonRegionFromImplSignature(span, _) => Some(span), | |
29967ef6 XL |
95 | RegionNameSource::AnonRegionFromArgument(ref highlight) |
96 | | RegionNameSource::AnonRegionFromOutput(ref highlight, _) => match *highlight { | |
3dfed10e XL |
97 | RegionNameHighlight::MatchedHirTy(span) |
98 | | RegionNameHighlight::MatchedAdtAndSegment(span) | |
29967ef6 XL |
99 | | RegionNameHighlight::CannotMatchHirTy(span, _) |
100 | | RegionNameHighlight::Occluded(span, _) => Some(span), | |
3dfed10e XL |
101 | }, |
102 | } | |
103 | } | |
104 | ||
923072b8 | 105 | pub(crate) fn highlight_region_name(&self, diag: &mut Diagnostic) { |
0bf4aa26 | 106 | match &self.source { |
e1599b0c XL |
107 | RegionNameSource::NamedFreeRegion(span) |
108 | | RegionNameSource::NamedEarlyBoundRegion(span) => { | |
04454e1e | 109 | diag.span_label(*span, format!("lifetime `{self}` defined here")); |
e1599b0c | 110 | } |
0bf4aa26 | 111 | RegionNameSource::SynthesizedFreeEnvRegion(span, note) => { |
04454e1e | 112 | diag.span_label(*span, format!("lifetime `{self}` represents this closure's body")); |
064997fb | 113 | diag.note(*note); |
e1599b0c | 114 | } |
3dfed10e XL |
115 | RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy( |
116 | span, | |
117 | type_name, | |
118 | )) => { | |
04454e1e | 119 | diag.span_label(*span, format!("has type `{type_name}`")); |
e1599b0c | 120 | } |
3dfed10e | 121 | RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::MatchedHirTy(span)) |
29967ef6 | 122 | | RegionNameSource::AnonRegionFromOutput(RegionNameHighlight::MatchedHirTy(span), _) |
dfeec247 | 123 | | RegionNameSource::AnonRegionFromAsyncFn(span) => { |
0bf4aa26 XL |
124 | diag.span_label( |
125 | *span, | |
04454e1e | 126 | format!("let's call the lifetime of this reference `{self}`"), |
0bf4aa26 | 127 | ); |
e1599b0c | 128 | } |
3dfed10e XL |
129 | RegionNameSource::AnonRegionFromArgument( |
130 | RegionNameHighlight::MatchedAdtAndSegment(span), | |
29967ef6 XL |
131 | ) |
132 | | RegionNameSource::AnonRegionFromOutput( | |
133 | RegionNameHighlight::MatchedAdtAndSegment(span), | |
134 | _, | |
3dfed10e | 135 | ) => { |
04454e1e | 136 | diag.span_label(*span, format!("let's call this `{self}`")); |
e1599b0c | 137 | } |
29967ef6 XL |
138 | RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::Occluded( |
139 | span, | |
140 | type_name, | |
141 | )) => { | |
142 | diag.span_label( | |
143 | *span, | |
04454e1e | 144 | format!("lifetime `{self}` appears in the type {type_name}"), |
29967ef6 XL |
145 | ); |
146 | } | |
147 | RegionNameSource::AnonRegionFromOutput( | |
148 | RegionNameHighlight::Occluded(span, type_name), | |
149 | mir_description, | |
150 | ) => { | |
151 | diag.span_label( | |
152 | *span, | |
153 | format!( | |
04454e1e | 154 | "return type{mir_description} `{type_name}` contains a lifetime `{self}`" |
29967ef6 XL |
155 | ), |
156 | ); | |
157 | } | |
0bf4aa26 XL |
158 | RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => { |
159 | diag.span_label( | |
160 | *span, | |
04454e1e | 161 | format!("lifetime `{self}` appears in the type of `{upvar_name}`"), |
0bf4aa26 | 162 | ); |
e1599b0c | 163 | } |
29967ef6 XL |
164 | RegionNameSource::AnonRegionFromOutput( |
165 | RegionNameHighlight::CannotMatchHirTy(span, type_name), | |
166 | mir_description, | |
167 | ) => { | |
04454e1e | 168 | diag.span_label(*span, format!("return type{mir_description} is {type_name}")); |
dfeec247 | 169 | } |
48663c56 | 170 | RegionNameSource::AnonRegionFromYieldTy(span, type_name) => { |
04454e1e | 171 | diag.span_label(*span, format!("yield type is {type_name}")); |
48663c56 | 172 | } |
923072b8 FG |
173 | RegionNameSource::AnonRegionFromImplSignature(span, location) => { |
174 | diag.span_label( | |
175 | *span, | |
176 | format!("lifetime `{self}` appears in the `impl`'s {location}"), | |
177 | ); | |
178 | } | |
dfeec247 | 179 | RegionNameSource::Static => {} |
0bf4aa26 XL |
180 | } |
181 | } | |
182 | } | |
183 | ||
184 | impl Display for RegionName { | |
9fa01778 | 185 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
0bf4aa26 XL |
186 | write!(f, "{}", self.name) |
187 | } | |
188 | } | |
189 | ||
dfeec247 | 190 | impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { |
923072b8 | 191 | pub(crate) fn mir_def_id(&self) -> hir::def_id::LocalDefId { |
064997fb | 192 | self.body.source.def_id().expect_local() |
29967ef6 XL |
193 | } |
194 | ||
923072b8 | 195 | pub(crate) fn mir_hir_id(&self) -> hir::HirId { |
29967ef6 XL |
196 | self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id()) |
197 | } | |
198 | ||
dfeec247 XL |
199 | /// Generate a synthetic region named `'N`, where `N` is the next value of the counter. Then, |
200 | /// increment the counter. | |
201 | /// | |
202 | /// This is _not_ idempotent. Call `give_region_a_name` when possible. | |
203 | fn synthesize_region_name(&self) -> Symbol { | |
204 | let c = self.next_region_name.replace_with(|counter| *counter + 1); | |
205 | Symbol::intern(&format!("'{:?}", c)) | |
206 | } | |
207 | ||
8faf50e0 XL |
208 | /// Maps from an internal MIR region vid to something that we can |
209 | /// report to the user. In some cases, the region vids will map | |
210 | /// directly to lifetimes that the user has a name for (e.g., | |
211 | /// `'static`). But frequently they will not, in which case we | |
212 | /// have to find some way to identify the lifetime to the user. To | |
213 | /// that end, this function takes a "diagnostic" so that it can | |
214 | /// create auxiliary notes as needed. | |
215 | /// | |
dfeec247 XL |
216 | /// The names are memoized, so this is both cheap to recompute and idempotent. |
217 | /// | |
8faf50e0 XL |
218 | /// Example (function arguments): |
219 | /// | |
220 | /// Suppose we are trying to give a name to the lifetime of the | |
221 | /// reference `x`: | |
222 | /// | |
04454e1e | 223 | /// ```ignore (pseudo-rust) |
8faf50e0 XL |
224 | /// fn foo(x: &u32) { .. } |
225 | /// ``` | |
226 | /// | |
227 | /// This function would create a label like this: | |
228 | /// | |
ba9703b0 | 229 | /// ```text |
8faf50e0 XL |
230 | /// | fn foo(x: &u32) { .. } |
231 | /// ------- fully elaborated type of `x` is `&'1 u32` | |
232 | /// ``` | |
233 | /// | |
234 | /// and then return the name `'1` for us to use. | |
923072b8 | 235 | pub(crate) fn give_region_a_name(&self, fr: RegionVid) -> Option<RegionName> { |
dfeec247 XL |
236 | debug!( |
237 | "give_region_a_name(fr={:?}, counter={:?})", | |
238 | fr, | |
239 | self.next_region_name.try_borrow().unwrap() | |
240 | ); | |
8faf50e0 | 241 | |
dfeec247 | 242 | assert!(self.regioncx.universal_regions().is_universal_region(fr)); |
8faf50e0 | 243 | |
dfeec247 | 244 | if let Some(value) = self.region_names.try_borrow_mut().unwrap().get(&fr) { |
e1599b0c XL |
245 | return Some(value.clone()); |
246 | } | |
247 | ||
248 | let value = self | |
dfeec247 XL |
249 | .give_name_from_error_region(fr) |
250 | .or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr)) | |
251 | .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr)) | |
252 | .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr)) | |
923072b8 FG |
253 | .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr)) |
254 | .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr)); | |
b7449926 | 255 | |
e1599b0c | 256 | if let Some(ref value) = value { |
dfeec247 | 257 | self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone()); |
e1599b0c XL |
258 | } |
259 | ||
b7449926 XL |
260 | debug!("give_region_a_name: gave name {:?}", value); |
261 | value | |
8faf50e0 XL |
262 | } |
263 | ||
9fa01778 | 264 | /// Checks for the case where `fr` maps to something that the |
8faf50e0 XL |
265 | /// *user* has a name for. In that case, we'll be able to map |
266 | /// `fr` to a `Region<'tcx>`, and that region will be one of | |
267 | /// named variants. | |
f2b60f7d | 268 | #[instrument(level = "trace", skip(self))] |
dfeec247 | 269 | fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> { |
8faf50e0 | 270 | let error_region = self.to_error_region(fr)?; |
b7449926 | 271 | |
dfeec247 XL |
272 | let tcx = self.infcx.tcx; |
273 | ||
8faf50e0 | 274 | debug!("give_region_a_name: error_region = {:?}", error_region); |
5099ac24 | 275 | match *error_region { |
b7449926 XL |
276 | ty::ReEarlyBound(ebr) => { |
277 | if ebr.has_name() { | |
60c5eb7d | 278 | let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP); |
0bf4aa26 XL |
279 | Some(RegionName { |
280 | name: ebr.name, | |
e1599b0c | 281 | source: RegionNameSource::NamedEarlyBoundRegion(span), |
0bf4aa26 | 282 | }) |
b7449926 XL |
283 | } else { |
284 | None | |
285 | } | |
286 | } | |
8faf50e0 | 287 | |
dfeec247 XL |
288 | ty::ReStatic => { |
289 | Some(RegionName { name: kw::StaticLifetime, source: RegionNameSource::Static }) | |
290 | } | |
8faf50e0 XL |
291 | |
292 | ty::ReFree(free_region) => match free_region.bound_region { | |
fc512014 | 293 | ty::BoundRegionKind::BrNamed(region_def_id, name) => { |
60c5eb7d XL |
294 | // Get the span to point to, even if we don't use the name. |
295 | let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP); | |
dfeec247 XL |
296 | debug!( |
297 | "bound region named: {:?}, is_named: {:?}", | |
298 | name, | |
299 | free_region.bound_region.is_named() | |
300 | ); | |
60c5eb7d XL |
301 | |
302 | if free_region.bound_region.is_named() { | |
303 | // A named region that is actually named. | |
dfeec247 | 304 | Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) }) |
923072b8 | 305 | } else if let hir::IsAsync::Async = tcx.asyncness(self.mir_hir_id().owner) { |
60c5eb7d XL |
306 | // If we spuriously thought that the region is named, we should let the |
307 | // system generate a true name for error messages. Currently this can | |
308 | // happen if we have an elided name in an async fn for example: the | |
309 | // compiler will generate a region named `'_`, but reporting such a name is | |
310 | // not actually useful, so we synthesize a name for it instead. | |
dfeec247 | 311 | let name = self.synthesize_region_name(); |
60c5eb7d XL |
312 | Some(RegionName { |
313 | name, | |
314 | source: RegionNameSource::AnonRegionFromAsyncFn(span), | |
315 | }) | |
923072b8 FG |
316 | } else { |
317 | None | |
60c5eb7d | 318 | } |
e1599b0c | 319 | } |
8faf50e0 | 320 | |
fc512014 | 321 | ty::BoundRegionKind::BrEnv => { |
dfeec247 | 322 | let def_ty = self.regioncx.universal_regions().defining_ty; |
b7449926 | 323 | |
5099ac24 | 324 | let DefiningTy::Closure(_, substs) = def_ty else { |
b7449926 XL |
325 | // Can't have BrEnv in functions, constants or generators. |
326 | bug!("BrEnv outside of closure."); | |
5099ac24 | 327 | }; |
064997fb | 328 | let hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }) |
923072b8 FG |
329 | = tcx.hir().expect_expr(self.mir_hir_id()).kind |
330 | else { | |
5099ac24 FG |
331 | bug!("Closure is not defined by a closure expr"); |
332 | }; | |
333 | let region_name = self.synthesize_region_name(); | |
334 | ||
335 | let closure_kind_ty = substs.as_closure().kind_ty(); | |
336 | let note = match closure_kind_ty.to_opt_closure_kind() { | |
337 | Some(ty::ClosureKind::Fn) => { | |
338 | "closure implements `Fn`, so references to captured variables \ | |
339 | can't escape the closure" | |
340 | } | |
341 | Some(ty::ClosureKind::FnMut) => { | |
342 | "closure implements `FnMut`, so references to captured variables \ | |
343 | can't escape the closure" | |
344 | } | |
345 | Some(ty::ClosureKind::FnOnce) => { | |
346 | bug!("BrEnv in a `FnOnce` closure"); | |
347 | } | |
348 | None => bug!("Closure kind not inferred in borrow check"), | |
349 | }; | |
350 | ||
351 | Some(RegionName { | |
352 | name: region_name, | |
064997fb | 353 | source: RegionNameSource::SynthesizedFreeEnvRegion(fn_decl_span, note), |
5099ac24 | 354 | }) |
8faf50e0 XL |
355 | } |
356 | ||
fc512014 | 357 | ty::BoundRegionKind::BrAnon(_) => None, |
8faf50e0 XL |
358 | }, |
359 | ||
f2b60f7d | 360 | ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None, |
8faf50e0 XL |
361 | } |
362 | } | |
363 | ||
9fa01778 | 364 | /// Finds an argument that contains `fr` and label it with a fully |
8faf50e0 XL |
365 | /// elaborated type, returning something like `'1`. Result looks |
366 | /// like: | |
367 | /// | |
ba9703b0 | 368 | /// ```text |
8faf50e0 XL |
369 | /// | fn foo(x: &u32) { .. } |
370 | /// ------- fully elaborated type of `x` is `&'1 u32` | |
371 | /// ``` | |
f2b60f7d | 372 | #[instrument(level = "trace", skip(self))] |
8faf50e0 XL |
373 | fn give_name_if_anonymous_region_appears_in_arguments( |
374 | &self, | |
8faf50e0 | 375 | fr: RegionVid, |
0bf4aa26 | 376 | ) -> Option<RegionName> { |
dfeec247 XL |
377 | let implicit_inputs = self.regioncx.universal_regions().defining_ty.implicit_inputs(); |
378 | let argument_index = self.regioncx.get_argument_index_for_region(self.infcx.tcx, fr)?; | |
379 | ||
380 | let arg_ty = self.regioncx.universal_regions().unnormalized_input_tys | |
381 | [implicit_inputs + argument_index]; | |
3dfed10e XL |
382 | let (_, span) = self.regioncx.get_argument_name_and_span_for_region( |
383 | &self.body, | |
384 | &self.local_names, | |
385 | argument_index, | |
386 | ); | |
8faf50e0 | 387 | |
29967ef6 XL |
388 | let highlight = self |
389 | .get_argument_hir_ty_for_highlighting(argument_index) | |
3dfed10e | 390 | .and_then(|arg_hir_ty| self.highlight_if_we_can_match_hir_ty(fr, arg_ty, arg_hir_ty)) |
29967ef6 | 391 | .unwrap_or_else(|| { |
3dfed10e XL |
392 | // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to |
393 | // the anonymous region. If it succeeds, the `synthesize_region_name` call below | |
394 | // will increment the counter, "reserving" the number we just used. | |
395 | let counter = *self.next_region_name.try_borrow().unwrap(); | |
396 | self.highlight_if_we_cannot_match_hir_ty(fr, arg_ty, span, counter) | |
29967ef6 XL |
397 | }); |
398 | ||
399 | Some(RegionName { | |
400 | name: self.synthesize_region_name(), | |
401 | source: RegionNameSource::AnonRegionFromArgument(highlight), | |
402 | }) | |
8faf50e0 XL |
403 | } |
404 | ||
3dfed10e | 405 | fn get_argument_hir_ty_for_highlighting( |
8faf50e0 | 406 | &self, |
8faf50e0 | 407 | argument_index: usize, |
3dfed10e | 408 | ) -> Option<&hir::Ty<'tcx>> { |
29967ef6 | 409 | let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(self.mir_hir_id())?; |
dfeec247 | 410 | let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?; |
e74abb32 | 411 | match argument_hir_ty.kind { |
8faf50e0 XL |
412 | // This indicates a variable with no type annotation, like |
413 | // `|x|`... in that case, we can't highlight the type but | |
414 | // must highlight the variable. | |
e74abb32 XL |
415 | // NOTE(eddyb) this is handled in/by the sole caller |
416 | // (`give_name_if_anonymous_region_appears_in_arguments`). | |
417 | hir::TyKind::Infer => None, | |
8faf50e0 | 418 | |
3dfed10e | 419 | _ => Some(argument_hir_ty), |
8faf50e0 XL |
420 | } |
421 | } | |
422 | ||
423 | /// Attempts to highlight the specific part of a type in an argument | |
424 | /// that has no type annotation. | |
425 | /// For example, we might produce an annotation like this: | |
426 | /// | |
ba9703b0 | 427 | /// ```text |
8faf50e0 XL |
428 | /// | foo(|a, b| b) |
429 | /// | - - | |
430 | /// | | | | |
431 | /// | | has type `&'1 u32` | |
432 | /// | has type `&'2 u32` | |
433 | /// ``` | |
3dfed10e | 434 | fn highlight_if_we_cannot_match_hir_ty( |
8faf50e0 | 435 | &self, |
8faf50e0 | 436 | needle_fr: RegionVid, |
3dfed10e XL |
437 | ty: Ty<'tcx>, |
438 | span: Span, | |
439 | counter: usize, | |
29967ef6 | 440 | ) -> RegionNameHighlight { |
5099ac24 | 441 | let mut highlight = RegionHighlightMode::new(self.infcx.tcx); |
e1599b0c | 442 | highlight.highlighting_region_vid(needle_fr, counter); |
1b1a35ee XL |
443 | let type_name = |
444 | self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name; | |
8faf50e0 | 445 | |
b7449926 | 446 | debug!( |
3dfed10e | 447 | "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", |
b7449926 XL |
448 | type_name, needle_fr |
449 | ); | |
04454e1e | 450 | if type_name.contains(&format!("'{counter}")) { |
8faf50e0 | 451 | // Only add a label if we can confirm that a region was labelled. |
29967ef6 | 452 | RegionNameHighlight::CannotMatchHirTy(span, type_name) |
8faf50e0 | 453 | } else { |
29967ef6 | 454 | RegionNameHighlight::Occluded(span, type_name) |
3dfed10e | 455 | } |
8faf50e0 XL |
456 | } |
457 | ||
458 | /// Attempts to highlight the specific part of a type annotation | |
459 | /// that contains the anonymous reference we want to give a name | |
460 | /// to. For example, we might produce an annotation like this: | |
461 | /// | |
ba9703b0 | 462 | /// ```text |
9fa01778 | 463 | /// | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item = &T>> { |
8faf50e0 XL |
464 | /// | - let's call the lifetime of this reference `'1` |
465 | /// ``` | |
466 | /// | |
3dfed10e | 467 | /// the way this works is that we match up `ty`, which is |
8faf50e0 | 468 | /// a `Ty<'tcx>` (the internal form of the type) with |
3dfed10e | 469 | /// `hir_ty`, a `hir::Ty` (the syntax of the type |
8faf50e0 XL |
470 | /// annotation). We are descending through the types stepwise, |
471 | /// looking in to find the region `needle_fr` in the internal | |
9fa01778 | 472 | /// type. Once we find that, we can use the span of the `hir::Ty` |
8faf50e0 XL |
473 | /// to add the highlight. |
474 | /// | |
e1599b0c | 475 | /// This is a somewhat imperfect process, so along the way we also |
8faf50e0 XL |
476 | /// keep track of the **closest** type we've found. If we fail to |
477 | /// find the exact `&` or `'_` to highlight, then we may fall back | |
478 | /// to highlighting that closest type instead. | |
3dfed10e | 479 | fn highlight_if_we_can_match_hir_ty( |
8faf50e0 | 480 | &self, |
8faf50e0 | 481 | needle_fr: RegionVid, |
3dfed10e XL |
482 | ty: Ty<'tcx>, |
483 | hir_ty: &hir::Ty<'_>, | |
484 | ) -> Option<RegionNameHighlight> { | |
485 | let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> = &mut vec![(ty, hir_ty)]; | |
8faf50e0 | 486 | |
8faf50e0 | 487 | while let Some((ty, hir_ty)) = search_stack.pop() { |
5e7ed085 | 488 | match (ty.kind(), &hir_ty.kind) { |
3dfed10e | 489 | // Check if the `ty` is `&'X ..` where `'X` |
8faf50e0 XL |
490 | // is the region we are looking for -- if so, and we have a `&T` |
491 | // on the RHS, then we want to highlight the `&` like so: | |
492 | // | |
493 | // & | |
494 | // - let's call the lifetime of this reference `'1` | |
495 | ( | |
b7449926 | 496 | ty::Ref(region, referent_ty, _), |
8faf50e0 XL |
497 | hir::TyKind::Rptr(_lifetime, referent_hir_ty), |
498 | ) => { | |
499 | if region.to_region_vid() == needle_fr { | |
8faf50e0 | 500 | // Just grab the first character, the `&`. |
dfeec247 | 501 | let source_map = self.infcx.tcx.sess.source_map(); |
b7449926 | 502 | let ampersand_span = source_map.start_point(hir_ty.span); |
8faf50e0 | 503 | |
3dfed10e | 504 | return Some(RegionNameHighlight::MatchedHirTy(ampersand_span)); |
8faf50e0 XL |
505 | } |
506 | ||
507 | // Otherwise, let's descend into the referent types. | |
5099ac24 | 508 | search_stack.push((*referent_ty, &referent_hir_ty.ty)); |
8faf50e0 XL |
509 | } |
510 | ||
511 | // Match up something like `Foo<'1>` | |
512 | ( | |
b7449926 | 513 | ty::Adt(_adt_def, substs), |
8faf50e0 XL |
514 | hir::TyKind::Path(hir::QPath::Resolved(None, path)), |
515 | ) => { | |
48663c56 | 516 | match path.res { |
0bf4aa26 XL |
517 | // Type parameters of the type alias have no reason to |
518 | // be the same as those of the ADT. | |
519 | // FIXME: We should be able to do something similar to | |
520 | // match_adt_and_segment in this case. | |
48663c56 | 521 | Res::Def(DefKind::TyAlias, _) => (), |
dfeec247 XL |
522 | _ => { |
523 | if let Some(last_segment) = path.segments.last() { | |
3dfed10e | 524 | if let Some(highlight) = self.match_adt_and_segment( |
dfeec247 XL |
525 | substs, |
526 | needle_fr, | |
527 | last_segment, | |
528 | search_stack, | |
529 | ) { | |
3dfed10e | 530 | return Some(highlight); |
dfeec247 | 531 | } |
0bf4aa26 | 532 | } |
8faf50e0 XL |
533 | } |
534 | } | |
535 | } | |
536 | ||
537 | // The following cases don't have lifetimes, so we | |
538 | // just worry about trying to match up the rustc type | |
539 | // with the HIR types: | |
5e7ed085 FG |
540 | (&ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => { |
541 | search_stack.extend(iter::zip(elem_tys, *elem_hir_tys)); | |
8faf50e0 XL |
542 | } |
543 | ||
b7449926 XL |
544 | (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty)) |
545 | | (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => { | |
5099ac24 | 546 | search_stack.push((*elem_ty, elem_hir_ty)); |
8faf50e0 XL |
547 | } |
548 | ||
b7449926 | 549 | (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => { |
8faf50e0 XL |
550 | search_stack.push((mut_ty.ty, &mut_hir_ty.ty)); |
551 | } | |
552 | ||
553 | _ => { | |
554 | // FIXME there are other cases that we could trace | |
555 | } | |
556 | } | |
557 | } | |
558 | ||
ba9703b0 | 559 | None |
8faf50e0 XL |
560 | } |
561 | ||
562 | /// We've found an enum/struct/union type with the substitutions | |
563 | /// `substs` and -- in the HIR -- a path type with the final | |
564 | /// segment `last_segment`. Try to find a `'_` to highlight in | |
565 | /// the generic args (or, if not, to produce new zipped pairs of | |
566 | /// types+hir to search through). | |
567 | fn match_adt_and_segment<'hir>( | |
568 | &self, | |
532ac7d7 | 569 | substs: SubstsRef<'tcx>, |
8faf50e0 | 570 | needle_fr: RegionVid, |
dfeec247 XL |
571 | last_segment: &'hir hir::PathSegment<'hir>, |
572 | search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>, | |
3dfed10e | 573 | ) -> Option<RegionNameHighlight> { |
8faf50e0 XL |
574 | // Did the user give explicit arguments? (e.g., `Foo<..>`) |
575 | let args = last_segment.args.as_ref()?; | |
e1599b0c XL |
576 | let lifetime = |
577 | self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; | |
8faf50e0 | 578 | match lifetime.name { |
923072b8 | 579 | hir::LifetimeName::Param(_, hir::ParamName::Plain(_) | hir::ParamName::Error) |
0bf4aa26 | 580 | | hir::LifetimeName::Error |
923072b8 | 581 | | hir::LifetimeName::Static => { |
3dfed10e XL |
582 | let lifetime_span = lifetime.span; |
583 | Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span)) | |
8faf50e0 XL |
584 | } |
585 | ||
923072b8 FG |
586 | hir::LifetimeName::Param(_, hir::ParamName::Fresh) |
587 | | hir::LifetimeName::ImplicitObjectLifetimeDefault | |
064997fb | 588 | | hir::LifetimeName::Infer => { |
8faf50e0 XL |
589 | // In this case, the user left off the lifetime; so |
590 | // they wrote something like: | |
591 | // | |
592 | // ``` | |
593 | // x: Foo<T> | |
594 | // ``` | |
595 | // | |
596 | // where the fully elaborated form is `Foo<'_, '1, | |
597 | // T>`. We don't consider this a match; instead we let | |
598 | // the "fully elaborated" type fallback above handle | |
599 | // it. | |
0bf4aa26 | 600 | None |
8faf50e0 XL |
601 | } |
602 | } | |
603 | } | |
604 | ||
605 | /// We've found an enum/struct/union type with the substitutions | |
606 | /// `substs` and -- in the HIR -- a path with the generic | |
607 | /// arguments `args`. If `needle_fr` appears in the args, return | |
608 | /// the `hir::Lifetime` that corresponds to it. If not, push onto | |
609 | /// `search_stack` the types+hir to search through. | |
610 | fn try_match_adt_and_generic_args<'hir>( | |
611 | &self, | |
532ac7d7 | 612 | substs: SubstsRef<'tcx>, |
8faf50e0 | 613 | needle_fr: RegionVid, |
dfeec247 XL |
614 | args: &'hir hir::GenericArgs<'hir>, |
615 | search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>, | |
8faf50e0 | 616 | ) -> Option<&'hir hir::Lifetime> { |
cdc7bbd5 | 617 | for (kind, hir_arg) in iter::zip(substs, args.args) { |
8faf50e0 | 618 | match (kind.unpack(), hir_arg) { |
e74abb32 | 619 | (GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => { |
8faf50e0 XL |
620 | if r.to_region_vid() == needle_fr { |
621 | return Some(lt); | |
622 | } | |
623 | } | |
624 | ||
e74abb32 | 625 | (GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => { |
8faf50e0 XL |
626 | search_stack.push((ty, hir_ty)); |
627 | } | |
628 | ||
e74abb32 | 629 | (GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => { |
532ac7d7 XL |
630 | // Lifetimes cannot be found in consts, so we don't need |
631 | // to search anything here. | |
632 | } | |
633 | ||
ba9703b0 XL |
634 | ( |
635 | GenericArgKind::Lifetime(_) | |
636 | | GenericArgKind::Type(_) | |
637 | | GenericArgKind::Const(_), | |
638 | _, | |
639 | ) => { | |
6a06907d XL |
640 | // HIR lowering sometimes doesn't catch this in erroneous |
641 | // programs, so we need to use delay_span_bug here. See #82126. | |
642 | self.infcx.tcx.sess.delay_span_bug( | |
8faf50e0 | 643 | hir_arg.span(), |
6a06907d | 644 | &format!("unmatched subst and hir arg: found {:?} vs {:?}", kind, hir_arg), |
8faf50e0 XL |
645 | ); |
646 | } | |
647 | } | |
648 | } | |
649 | ||
650 | None | |
651 | } | |
652 | ||
9fa01778 | 653 | /// Finds a closure upvar that contains `fr` and label it with a |
8faf50e0 XL |
654 | /// fully elaborated type, returning something like `'1`. Result |
655 | /// looks like: | |
656 | /// | |
ba9703b0 | 657 | /// ```text |
8faf50e0 XL |
658 | /// | let x = Some(&22); |
659 | /// - fully elaborated type of `x` is `Option<&'1 u32>` | |
660 | /// ``` | |
f2b60f7d | 661 | #[instrument(level = "trace", skip(self))] |
dfeec247 XL |
662 | fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> { |
663 | let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?; | |
664 | let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( | |
665 | self.infcx.tcx, | |
666 | &self.upvars, | |
667 | upvar_index, | |
668 | ); | |
669 | let region_name = self.synthesize_region_name(); | |
8faf50e0 | 670 | |
0bf4aa26 XL |
671 | Some(RegionName { |
672 | name: region_name, | |
064997fb | 673 | source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), |
0bf4aa26 | 674 | }) |
8faf50e0 XL |
675 | } |
676 | ||
9fa01778 | 677 | /// Checks for arguments appearing in the (closure) return type. It |
8faf50e0 XL |
678 | /// must be a closure since, in a free fn, such an argument would |
679 | /// have to either also appear in an argument (if using elision) | |
680 | /// or be early bound (named, not in argument). | |
f2b60f7d | 681 | #[instrument(level = "trace", skip(self))] |
dfeec247 XL |
682 | fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> { |
683 | let tcx = self.infcx.tcx; | |
29967ef6 | 684 | let hir = tcx.hir(); |
b7449926 | 685 | |
dfeec247 XL |
686 | let return_ty = self.regioncx.universal_regions().unnormalized_output_ty; |
687 | debug!("give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty); | |
48663c56 | 688 | if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) { |
8faf50e0 XL |
689 | return None; |
690 | } | |
691 | ||
29967ef6 | 692 | let mir_hir_id = self.mir_hir_id(); |
b7449926 | 693 | |
29967ef6 | 694 | let (return_span, mir_description, hir_ty) = match hir.get(mir_hir_id) { |
a1dfa0c6 | 695 | hir::Node::Expr(hir::Expr { |
064997fb | 696 | kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, .. }), |
a1dfa0c6 | 697 | .. |
29967ef6 | 698 | }) => { |
923072b8 | 699 | let (mut span, mut hir_ty) = match fn_decl.output { |
29967ef6 | 700 | hir::FnRetTy::DefaultReturn(_) => { |
064997fb | 701 | (tcx.sess.source_map().end_point(fn_decl_span), None) |
29967ef6 | 702 | } |
923072b8 | 703 | hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)), |
29967ef6 | 704 | }; |
064997fb | 705 | let mir_description = match hir.body(body).generator_kind { |
29967ef6 XL |
706 | Some(hir::GeneratorKind::Async(gen)) => match gen { |
707 | hir::AsyncGeneratorKind::Block => " of async block", | |
708 | hir::AsyncGeneratorKind::Closure => " of async closure", | |
709 | hir::AsyncGeneratorKind::Fn => { | |
5099ac24 | 710 | let parent_item = hir.get_by_def_id(hir.get_parent_item(mir_hir_id)); |
29967ef6 XL |
711 | let output = &parent_item |
712 | .fn_decl() | |
713 | .expect("generator lowered from async fn should be in fn") | |
714 | .output; | |
715 | span = output.span(); | |
716 | if let hir::FnRetTy::Return(ret) = output { | |
717 | hir_ty = Some(self.get_future_inner_return_ty(*ret)); | |
718 | } | |
719 | " of async function" | |
720 | } | |
721 | }, | |
722 | Some(hir::GeneratorKind::Gen) => " of generator", | |
723 | None => " of closure", | |
724 | }; | |
725 | (span, mir_description, hir_ty) | |
726 | } | |
727 | node => match node.fn_decl() { | |
728 | Some(fn_decl) => { | |
729 | let hir_ty = match fn_decl.output { | |
730 | hir::FnRetTy::DefaultReturn(_) => None, | |
731 | hir::FnRetTy::Return(ty) => Some(ty), | |
732 | }; | |
733 | (fn_decl.output.span(), "", hir_ty) | |
734 | } | |
735 | None => (self.body.span, "", None), | |
736 | }, | |
a1dfa0c6 | 737 | }; |
b7449926 | 738 | |
29967ef6 XL |
739 | let highlight = hir_ty |
740 | .and_then(|hir_ty| self.highlight_if_we_can_match_hir_ty(fr, return_ty, hir_ty)) | |
741 | .unwrap_or_else(|| { | |
742 | // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to | |
743 | // the anonymous region. If it succeeds, the `synthesize_region_name` call below | |
744 | // will increment the counter, "reserving" the number we just used. | |
745 | let counter = *self.next_region_name.try_borrow().unwrap(); | |
746 | self.highlight_if_we_cannot_match_hir_ty(fr, return_ty, return_span, counter) | |
747 | }); | |
748 | ||
0bf4aa26 | 749 | Some(RegionName { |
dfeec247 | 750 | name: self.synthesize_region_name(), |
064997fb | 751 | source: RegionNameSource::AnonRegionFromOutput(highlight, mir_description), |
0bf4aa26 | 752 | }) |
8faf50e0 XL |
753 | } |
754 | ||
29967ef6 XL |
755 | /// From the [`hir::Ty`] of an async function's lowered return type, |
756 | /// retrieve the `hir::Ty` representing the type the user originally wrote. | |
757 | /// | |
758 | /// e.g. given the function: | |
759 | /// | |
760 | /// ``` | |
04454e1e | 761 | /// async fn foo() -> i32 { 2 } |
29967ef6 XL |
762 | /// ``` |
763 | /// | |
764 | /// this function, given the lowered return type of `foo`, an [`OpaqueDef`] that implements `Future<Output=i32>`, | |
765 | /// returns the `i32`. | |
766 | /// | |
767 | /// [`OpaqueDef`]: hir::TyKind::OpaqueDef | |
768 | fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { | |
769 | let hir = self.infcx.tcx.hir(); | |
770 | ||
f2b60f7d | 771 | let hir::TyKind::OpaqueDef(id, _, _) = hir_ty.kind else { |
29967ef6 XL |
772 | span_bug!( |
773 | hir_ty.span, | |
774 | "lowered return type of async fn is not OpaqueDef: {:?}", | |
775 | hir_ty | |
776 | ); | |
5099ac24 FG |
777 | }; |
778 | let opaque_ty = hir.item(id); | |
779 | if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { | |
780 | bounds: | |
781 | [ | |
782 | hir::GenericBound::LangItemTrait( | |
783 | hir::LangItem::Future, | |
784 | _, | |
785 | _, | |
786 | hir::GenericArgs { | |
787 | bindings: | |
788 | [ | |
789 | hir::TypeBinding { | |
790 | ident: Ident { name: sym::Output, .. }, | |
791 | kind: | |
792 | hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) }, | |
793 | .. | |
794 | }, | |
795 | ], | |
796 | .. | |
797 | }, | |
798 | ), | |
799 | ], | |
800 | .. | |
801 | }) = opaque_ty.kind | |
802 | { | |
803 | ty | |
804 | } else { | |
805 | span_bug!( | |
806 | hir_ty.span, | |
807 | "bounds from lowered return type of async fn did not match expected format: {:?}", | |
808 | opaque_ty | |
809 | ); | |
29967ef6 XL |
810 | } |
811 | } | |
812 | ||
f2b60f7d | 813 | #[instrument(level = "trace", skip(self))] |
48663c56 XL |
814 | fn give_name_if_anonymous_region_appears_in_yield_ty( |
815 | &self, | |
48663c56 | 816 | fr: RegionVid, |
48663c56 XL |
817 | ) -> Option<RegionName> { |
818 | // Note: generators from `async fn` yield `()`, so we don't have to | |
819 | // worry about them here. | |
dfeec247 | 820 | let yield_ty = self.regioncx.universal_regions().yield_ty?; |
04454e1e | 821 | debug!("give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}", yield_ty); |
48663c56 | 822 | |
dfeec247 | 823 | let tcx = self.infcx.tcx; |
48663c56 XL |
824 | |
825 | if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) { | |
826 | return None; | |
827 | } | |
828 | ||
5099ac24 | 829 | let mut highlight = RegionHighlightMode::new(tcx); |
dfeec247 | 830 | highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); |
1b1a35ee XL |
831 | let type_name = |
832 | self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; | |
48663c56 | 833 | |
29967ef6 | 834 | let yield_span = match tcx.hir().get(self.mir_hir_id()) { |
48663c56 | 835 | hir::Node::Expr(hir::Expr { |
064997fb | 836 | kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), |
923072b8 | 837 | .. |
064997fb | 838 | }) => tcx.sess.source_map().end_point(fn_decl_span), |
dfeec247 | 839 | _ => self.body.span, |
48663c56 XL |
840 | }; |
841 | ||
842 | debug!( | |
843 | "give_name_if_anonymous_region_appears_in_yield_ty: \ | |
844 | type_name = {:?}, yield_span = {:?}", | |
dfeec247 | 845 | yield_span, type_name, |
48663c56 XL |
846 | ); |
847 | ||
848 | Some(RegionName { | |
dfeec247 | 849 | name: self.synthesize_region_name(), |
48663c56 XL |
850 | source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name), |
851 | }) | |
852 | } | |
923072b8 FG |
853 | |
854 | fn give_name_if_anonymous_region_appears_in_impl_signature( | |
855 | &self, | |
856 | fr: RegionVid, | |
857 | ) -> Option<RegionName> { | |
858 | let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else { | |
859 | return None; | |
860 | }; | |
861 | if region.has_name() { | |
862 | return None; | |
863 | }; | |
864 | ||
865 | let tcx = self.infcx.tcx; | |
866 | let body_parent_did = tcx.opt_parent(self.mir_def_id().to_def_id())?; | |
867 | if tcx.parent(region.def_id) != body_parent_did | |
868 | || tcx.def_kind(body_parent_did) != DefKind::Impl | |
869 | { | |
870 | return None; | |
871 | } | |
872 | ||
873 | let mut found = false; | |
064997fb | 874 | tcx.fold_regions(tcx.type_of(body_parent_did), |r: ty::Region<'tcx>, _| { |
923072b8 FG |
875 | if *r == ty::ReEarlyBound(region) { |
876 | found = true; | |
877 | } | |
878 | r | |
879 | }); | |
880 | ||
881 | Some(RegionName { | |
882 | name: self.synthesize_region_name(), | |
883 | source: RegionNameSource::AnonRegionFromImplSignature( | |
884 | tcx.def_span(region.def_id), | |
885 | // FIXME(compiler-errors): Does this ever actually show up | |
886 | // anywhere other than the self type? I couldn't create an | |
887 | // example of a `'_` in the impl's trait being referenceable. | |
888 | if found { "self type" } else { "header" }, | |
889 | ), | |
890 | }) | |
891 | } | |
8faf50e0 | 892 | } |