]>
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. | |
923072b8 | 268 | #[tracing::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 | ||
360 | ty::ReLateBound(..) | |
8faf50e0 | 361 | | ty::ReVar(..) |
0bf4aa26 | 362 | | ty::RePlaceholder(..) |
74b04a01 | 363 | | ty::ReEmpty(_) |
ba9703b0 | 364 | | ty::ReErased => None, |
8faf50e0 XL |
365 | } |
366 | } | |
367 | ||
9fa01778 | 368 | /// Finds an argument that contains `fr` and label it with a fully |
8faf50e0 XL |
369 | /// elaborated type, returning something like `'1`. Result looks |
370 | /// like: | |
371 | /// | |
ba9703b0 | 372 | /// ```text |
8faf50e0 XL |
373 | /// | fn foo(x: &u32) { .. } |
374 | /// ------- fully elaborated type of `x` is `&'1 u32` | |
375 | /// ``` | |
923072b8 | 376 | #[tracing::instrument(level = "trace", skip(self))] |
8faf50e0 XL |
377 | fn give_name_if_anonymous_region_appears_in_arguments( |
378 | &self, | |
8faf50e0 | 379 | fr: RegionVid, |
0bf4aa26 | 380 | ) -> Option<RegionName> { |
dfeec247 XL |
381 | let implicit_inputs = self.regioncx.universal_regions().defining_ty.implicit_inputs(); |
382 | let argument_index = self.regioncx.get_argument_index_for_region(self.infcx.tcx, fr)?; | |
383 | ||
384 | let arg_ty = self.regioncx.universal_regions().unnormalized_input_tys | |
385 | [implicit_inputs + argument_index]; | |
3dfed10e XL |
386 | let (_, span) = self.regioncx.get_argument_name_and_span_for_region( |
387 | &self.body, | |
388 | &self.local_names, | |
389 | argument_index, | |
390 | ); | |
8faf50e0 | 391 | |
29967ef6 XL |
392 | let highlight = self |
393 | .get_argument_hir_ty_for_highlighting(argument_index) | |
3dfed10e | 394 | .and_then(|arg_hir_ty| self.highlight_if_we_can_match_hir_ty(fr, arg_ty, arg_hir_ty)) |
29967ef6 | 395 | .unwrap_or_else(|| { |
3dfed10e XL |
396 | // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to |
397 | // the anonymous region. If it succeeds, the `synthesize_region_name` call below | |
398 | // will increment the counter, "reserving" the number we just used. | |
399 | let counter = *self.next_region_name.try_borrow().unwrap(); | |
400 | self.highlight_if_we_cannot_match_hir_ty(fr, arg_ty, span, counter) | |
29967ef6 XL |
401 | }); |
402 | ||
403 | Some(RegionName { | |
404 | name: self.synthesize_region_name(), | |
405 | source: RegionNameSource::AnonRegionFromArgument(highlight), | |
406 | }) | |
8faf50e0 XL |
407 | } |
408 | ||
3dfed10e | 409 | fn get_argument_hir_ty_for_highlighting( |
8faf50e0 | 410 | &self, |
8faf50e0 | 411 | argument_index: usize, |
3dfed10e | 412 | ) -> Option<&hir::Ty<'tcx>> { |
29967ef6 | 413 | let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(self.mir_hir_id())?; |
dfeec247 | 414 | let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?; |
e74abb32 | 415 | match argument_hir_ty.kind { |
8faf50e0 XL |
416 | // This indicates a variable with no type annotation, like |
417 | // `|x|`... in that case, we can't highlight the type but | |
418 | // must highlight the variable. | |
e74abb32 XL |
419 | // NOTE(eddyb) this is handled in/by the sole caller |
420 | // (`give_name_if_anonymous_region_appears_in_arguments`). | |
421 | hir::TyKind::Infer => None, | |
8faf50e0 | 422 | |
3dfed10e | 423 | _ => Some(argument_hir_ty), |
8faf50e0 XL |
424 | } |
425 | } | |
426 | ||
427 | /// Attempts to highlight the specific part of a type in an argument | |
428 | /// that has no type annotation. | |
429 | /// For example, we might produce an annotation like this: | |
430 | /// | |
ba9703b0 | 431 | /// ```text |
8faf50e0 XL |
432 | /// | foo(|a, b| b) |
433 | /// | - - | |
434 | /// | | | | |
435 | /// | | has type `&'1 u32` | |
436 | /// | has type `&'2 u32` | |
437 | /// ``` | |
3dfed10e | 438 | fn highlight_if_we_cannot_match_hir_ty( |
8faf50e0 | 439 | &self, |
8faf50e0 | 440 | needle_fr: RegionVid, |
3dfed10e XL |
441 | ty: Ty<'tcx>, |
442 | span: Span, | |
443 | counter: usize, | |
29967ef6 | 444 | ) -> RegionNameHighlight { |
5099ac24 | 445 | let mut highlight = RegionHighlightMode::new(self.infcx.tcx); |
e1599b0c | 446 | highlight.highlighting_region_vid(needle_fr, counter); |
1b1a35ee XL |
447 | let type_name = |
448 | self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name; | |
8faf50e0 | 449 | |
b7449926 | 450 | debug!( |
3dfed10e | 451 | "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", |
b7449926 XL |
452 | type_name, needle_fr |
453 | ); | |
04454e1e | 454 | if type_name.contains(&format!("'{counter}")) { |
8faf50e0 | 455 | // Only add a label if we can confirm that a region was labelled. |
29967ef6 | 456 | RegionNameHighlight::CannotMatchHirTy(span, type_name) |
8faf50e0 | 457 | } else { |
29967ef6 | 458 | RegionNameHighlight::Occluded(span, type_name) |
3dfed10e | 459 | } |
8faf50e0 XL |
460 | } |
461 | ||
462 | /// Attempts to highlight the specific part of a type annotation | |
463 | /// that contains the anonymous reference we want to give a name | |
464 | /// to. For example, we might produce an annotation like this: | |
465 | /// | |
ba9703b0 | 466 | /// ```text |
9fa01778 | 467 | /// | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item = &T>> { |
8faf50e0 XL |
468 | /// | - let's call the lifetime of this reference `'1` |
469 | /// ``` | |
470 | /// | |
3dfed10e | 471 | /// the way this works is that we match up `ty`, which is |
8faf50e0 | 472 | /// a `Ty<'tcx>` (the internal form of the type) with |
3dfed10e | 473 | /// `hir_ty`, a `hir::Ty` (the syntax of the type |
8faf50e0 XL |
474 | /// annotation). We are descending through the types stepwise, |
475 | /// looking in to find the region `needle_fr` in the internal | |
9fa01778 | 476 | /// type. Once we find that, we can use the span of the `hir::Ty` |
8faf50e0 XL |
477 | /// to add the highlight. |
478 | /// | |
e1599b0c | 479 | /// This is a somewhat imperfect process, so along the way we also |
8faf50e0 XL |
480 | /// keep track of the **closest** type we've found. If we fail to |
481 | /// find the exact `&` or `'_` to highlight, then we may fall back | |
482 | /// to highlighting that closest type instead. | |
3dfed10e | 483 | fn highlight_if_we_can_match_hir_ty( |
8faf50e0 | 484 | &self, |
8faf50e0 | 485 | needle_fr: RegionVid, |
3dfed10e XL |
486 | ty: Ty<'tcx>, |
487 | hir_ty: &hir::Ty<'_>, | |
488 | ) -> Option<RegionNameHighlight> { | |
489 | let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> = &mut vec![(ty, hir_ty)]; | |
8faf50e0 | 490 | |
8faf50e0 | 491 | while let Some((ty, hir_ty)) = search_stack.pop() { |
5e7ed085 | 492 | match (ty.kind(), &hir_ty.kind) { |
3dfed10e | 493 | // Check if the `ty` is `&'X ..` where `'X` |
8faf50e0 XL |
494 | // is the region we are looking for -- if so, and we have a `&T` |
495 | // on the RHS, then we want to highlight the `&` like so: | |
496 | // | |
497 | // & | |
498 | // - let's call the lifetime of this reference `'1` | |
499 | ( | |
b7449926 | 500 | ty::Ref(region, referent_ty, _), |
8faf50e0 XL |
501 | hir::TyKind::Rptr(_lifetime, referent_hir_ty), |
502 | ) => { | |
503 | if region.to_region_vid() == needle_fr { | |
8faf50e0 | 504 | // Just grab the first character, the `&`. |
dfeec247 | 505 | let source_map = self.infcx.tcx.sess.source_map(); |
b7449926 | 506 | let ampersand_span = source_map.start_point(hir_ty.span); |
8faf50e0 | 507 | |
3dfed10e | 508 | return Some(RegionNameHighlight::MatchedHirTy(ampersand_span)); |
8faf50e0 XL |
509 | } |
510 | ||
511 | // Otherwise, let's descend into the referent types. | |
5099ac24 | 512 | search_stack.push((*referent_ty, &referent_hir_ty.ty)); |
8faf50e0 XL |
513 | } |
514 | ||
515 | // Match up something like `Foo<'1>` | |
516 | ( | |
b7449926 | 517 | ty::Adt(_adt_def, substs), |
8faf50e0 XL |
518 | hir::TyKind::Path(hir::QPath::Resolved(None, path)), |
519 | ) => { | |
48663c56 | 520 | match path.res { |
0bf4aa26 XL |
521 | // Type parameters of the type alias have no reason to |
522 | // be the same as those of the ADT. | |
523 | // FIXME: We should be able to do something similar to | |
524 | // match_adt_and_segment in this case. | |
48663c56 | 525 | Res::Def(DefKind::TyAlias, _) => (), |
dfeec247 XL |
526 | _ => { |
527 | if let Some(last_segment) = path.segments.last() { | |
3dfed10e | 528 | if let Some(highlight) = self.match_adt_and_segment( |
dfeec247 XL |
529 | substs, |
530 | needle_fr, | |
531 | last_segment, | |
532 | search_stack, | |
533 | ) { | |
3dfed10e | 534 | return Some(highlight); |
dfeec247 | 535 | } |
0bf4aa26 | 536 | } |
8faf50e0 XL |
537 | } |
538 | } | |
539 | } | |
540 | ||
541 | // The following cases don't have lifetimes, so we | |
542 | // just worry about trying to match up the rustc type | |
543 | // with the HIR types: | |
5e7ed085 FG |
544 | (&ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => { |
545 | search_stack.extend(iter::zip(elem_tys, *elem_hir_tys)); | |
8faf50e0 XL |
546 | } |
547 | ||
b7449926 XL |
548 | (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty)) |
549 | | (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => { | |
5099ac24 | 550 | search_stack.push((*elem_ty, elem_hir_ty)); |
8faf50e0 XL |
551 | } |
552 | ||
b7449926 | 553 | (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => { |
8faf50e0 XL |
554 | search_stack.push((mut_ty.ty, &mut_hir_ty.ty)); |
555 | } | |
556 | ||
557 | _ => { | |
558 | // FIXME there are other cases that we could trace | |
559 | } | |
560 | } | |
561 | } | |
562 | ||
ba9703b0 | 563 | None |
8faf50e0 XL |
564 | } |
565 | ||
566 | /// We've found an enum/struct/union type with the substitutions | |
567 | /// `substs` and -- in the HIR -- a path type with the final | |
568 | /// segment `last_segment`. Try to find a `'_` to highlight in | |
569 | /// the generic args (or, if not, to produce new zipped pairs of | |
570 | /// types+hir to search through). | |
571 | fn match_adt_and_segment<'hir>( | |
572 | &self, | |
532ac7d7 | 573 | substs: SubstsRef<'tcx>, |
8faf50e0 | 574 | needle_fr: RegionVid, |
dfeec247 XL |
575 | last_segment: &'hir hir::PathSegment<'hir>, |
576 | search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>, | |
3dfed10e | 577 | ) -> Option<RegionNameHighlight> { |
8faf50e0 XL |
578 | // Did the user give explicit arguments? (e.g., `Foo<..>`) |
579 | let args = last_segment.args.as_ref()?; | |
e1599b0c XL |
580 | let lifetime = |
581 | self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; | |
8faf50e0 | 582 | match lifetime.name { |
923072b8 | 583 | hir::LifetimeName::Param(_, hir::ParamName::Plain(_) | hir::ParamName::Error) |
0bf4aa26 | 584 | | hir::LifetimeName::Error |
923072b8 | 585 | | hir::LifetimeName::Static => { |
3dfed10e XL |
586 | let lifetime_span = lifetime.span; |
587 | Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span)) | |
8faf50e0 XL |
588 | } |
589 | ||
923072b8 FG |
590 | hir::LifetimeName::Param(_, hir::ParamName::Fresh) |
591 | | hir::LifetimeName::ImplicitObjectLifetimeDefault | |
064997fb | 592 | | hir::LifetimeName::Infer => { |
8faf50e0 XL |
593 | // In this case, the user left off the lifetime; so |
594 | // they wrote something like: | |
595 | // | |
596 | // ``` | |
597 | // x: Foo<T> | |
598 | // ``` | |
599 | // | |
600 | // where the fully elaborated form is `Foo<'_, '1, | |
601 | // T>`. We don't consider this a match; instead we let | |
602 | // the "fully elaborated" type fallback above handle | |
603 | // it. | |
0bf4aa26 | 604 | None |
8faf50e0 XL |
605 | } |
606 | } | |
607 | } | |
608 | ||
609 | /// We've found an enum/struct/union type with the substitutions | |
610 | /// `substs` and -- in the HIR -- a path with the generic | |
611 | /// arguments `args`. If `needle_fr` appears in the args, return | |
612 | /// the `hir::Lifetime` that corresponds to it. If not, push onto | |
613 | /// `search_stack` the types+hir to search through. | |
614 | fn try_match_adt_and_generic_args<'hir>( | |
615 | &self, | |
532ac7d7 | 616 | substs: SubstsRef<'tcx>, |
8faf50e0 | 617 | needle_fr: RegionVid, |
dfeec247 XL |
618 | args: &'hir hir::GenericArgs<'hir>, |
619 | search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>, | |
8faf50e0 | 620 | ) -> Option<&'hir hir::Lifetime> { |
cdc7bbd5 | 621 | for (kind, hir_arg) in iter::zip(substs, args.args) { |
8faf50e0 | 622 | match (kind.unpack(), hir_arg) { |
e74abb32 | 623 | (GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => { |
8faf50e0 XL |
624 | if r.to_region_vid() == needle_fr { |
625 | return Some(lt); | |
626 | } | |
627 | } | |
628 | ||
e74abb32 | 629 | (GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => { |
8faf50e0 XL |
630 | search_stack.push((ty, hir_ty)); |
631 | } | |
632 | ||
e74abb32 | 633 | (GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => { |
532ac7d7 XL |
634 | // Lifetimes cannot be found in consts, so we don't need |
635 | // to search anything here. | |
636 | } | |
637 | ||
ba9703b0 XL |
638 | ( |
639 | GenericArgKind::Lifetime(_) | |
640 | | GenericArgKind::Type(_) | |
641 | | GenericArgKind::Const(_), | |
642 | _, | |
643 | ) => { | |
6a06907d XL |
644 | // HIR lowering sometimes doesn't catch this in erroneous |
645 | // programs, so we need to use delay_span_bug here. See #82126. | |
646 | self.infcx.tcx.sess.delay_span_bug( | |
8faf50e0 | 647 | hir_arg.span(), |
6a06907d | 648 | &format!("unmatched subst and hir arg: found {:?} vs {:?}", kind, hir_arg), |
8faf50e0 XL |
649 | ); |
650 | } | |
651 | } | |
652 | } | |
653 | ||
654 | None | |
655 | } | |
656 | ||
9fa01778 | 657 | /// Finds a closure upvar that contains `fr` and label it with a |
8faf50e0 XL |
658 | /// fully elaborated type, returning something like `'1`. Result |
659 | /// looks like: | |
660 | /// | |
ba9703b0 | 661 | /// ```text |
8faf50e0 XL |
662 | /// | let x = Some(&22); |
663 | /// - fully elaborated type of `x` is `Option<&'1 u32>` | |
664 | /// ``` | |
923072b8 | 665 | #[tracing::instrument(level = "trace", skip(self))] |
dfeec247 XL |
666 | fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> { |
667 | let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?; | |
668 | let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( | |
669 | self.infcx.tcx, | |
670 | &self.upvars, | |
671 | upvar_index, | |
672 | ); | |
673 | let region_name = self.synthesize_region_name(); | |
8faf50e0 | 674 | |
0bf4aa26 XL |
675 | Some(RegionName { |
676 | name: region_name, | |
064997fb | 677 | source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), |
0bf4aa26 | 678 | }) |
8faf50e0 XL |
679 | } |
680 | ||
9fa01778 | 681 | /// Checks for arguments appearing in the (closure) return type. It |
8faf50e0 XL |
682 | /// must be a closure since, in a free fn, such an argument would |
683 | /// have to either also appear in an argument (if using elision) | |
684 | /// or be early bound (named, not in argument). | |
923072b8 | 685 | #[tracing::instrument(level = "trace", skip(self))] |
dfeec247 XL |
686 | fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> { |
687 | let tcx = self.infcx.tcx; | |
29967ef6 | 688 | let hir = tcx.hir(); |
b7449926 | 689 | |
dfeec247 XL |
690 | let return_ty = self.regioncx.universal_regions().unnormalized_output_ty; |
691 | debug!("give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty); | |
48663c56 | 692 | if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) { |
8faf50e0 XL |
693 | return None; |
694 | } | |
695 | ||
29967ef6 | 696 | let mir_hir_id = self.mir_hir_id(); |
b7449926 | 697 | |
29967ef6 | 698 | let (return_span, mir_description, hir_ty) = match hir.get(mir_hir_id) { |
a1dfa0c6 | 699 | hir::Node::Expr(hir::Expr { |
064997fb | 700 | kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, .. }), |
a1dfa0c6 | 701 | .. |
29967ef6 | 702 | }) => { |
923072b8 | 703 | let (mut span, mut hir_ty) = match fn_decl.output { |
29967ef6 | 704 | hir::FnRetTy::DefaultReturn(_) => { |
064997fb | 705 | (tcx.sess.source_map().end_point(fn_decl_span), None) |
29967ef6 | 706 | } |
923072b8 | 707 | hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)), |
29967ef6 | 708 | }; |
064997fb | 709 | let mir_description = match hir.body(body).generator_kind { |
29967ef6 XL |
710 | Some(hir::GeneratorKind::Async(gen)) => match gen { |
711 | hir::AsyncGeneratorKind::Block => " of async block", | |
712 | hir::AsyncGeneratorKind::Closure => " of async closure", | |
713 | hir::AsyncGeneratorKind::Fn => { | |
5099ac24 | 714 | let parent_item = hir.get_by_def_id(hir.get_parent_item(mir_hir_id)); |
29967ef6 XL |
715 | let output = &parent_item |
716 | .fn_decl() | |
717 | .expect("generator lowered from async fn should be in fn") | |
718 | .output; | |
719 | span = output.span(); | |
720 | if let hir::FnRetTy::Return(ret) = output { | |
721 | hir_ty = Some(self.get_future_inner_return_ty(*ret)); | |
722 | } | |
723 | " of async function" | |
724 | } | |
725 | }, | |
726 | Some(hir::GeneratorKind::Gen) => " of generator", | |
727 | None => " of closure", | |
728 | }; | |
729 | (span, mir_description, hir_ty) | |
730 | } | |
731 | node => match node.fn_decl() { | |
732 | Some(fn_decl) => { | |
733 | let hir_ty = match fn_decl.output { | |
734 | hir::FnRetTy::DefaultReturn(_) => None, | |
735 | hir::FnRetTy::Return(ty) => Some(ty), | |
736 | }; | |
737 | (fn_decl.output.span(), "", hir_ty) | |
738 | } | |
739 | None => (self.body.span, "", None), | |
740 | }, | |
a1dfa0c6 | 741 | }; |
b7449926 | 742 | |
29967ef6 XL |
743 | let highlight = hir_ty |
744 | .and_then(|hir_ty| self.highlight_if_we_can_match_hir_ty(fr, return_ty, hir_ty)) | |
745 | .unwrap_or_else(|| { | |
746 | // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to | |
747 | // the anonymous region. If it succeeds, the `synthesize_region_name` call below | |
748 | // will increment the counter, "reserving" the number we just used. | |
749 | let counter = *self.next_region_name.try_borrow().unwrap(); | |
750 | self.highlight_if_we_cannot_match_hir_ty(fr, return_ty, return_span, counter) | |
751 | }); | |
752 | ||
0bf4aa26 | 753 | Some(RegionName { |
dfeec247 | 754 | name: self.synthesize_region_name(), |
064997fb | 755 | source: RegionNameSource::AnonRegionFromOutput(highlight, mir_description), |
0bf4aa26 | 756 | }) |
8faf50e0 XL |
757 | } |
758 | ||
29967ef6 XL |
759 | /// From the [`hir::Ty`] of an async function's lowered return type, |
760 | /// retrieve the `hir::Ty` representing the type the user originally wrote. | |
761 | /// | |
762 | /// e.g. given the function: | |
763 | /// | |
764 | /// ``` | |
04454e1e | 765 | /// async fn foo() -> i32 { 2 } |
29967ef6 XL |
766 | /// ``` |
767 | /// | |
768 | /// this function, given the lowered return type of `foo`, an [`OpaqueDef`] that implements `Future<Output=i32>`, | |
769 | /// returns the `i32`. | |
770 | /// | |
771 | /// [`OpaqueDef`]: hir::TyKind::OpaqueDef | |
772 | fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { | |
773 | let hir = self.infcx.tcx.hir(); | |
774 | ||
5099ac24 | 775 | let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else { |
29967ef6 XL |
776 | span_bug!( |
777 | hir_ty.span, | |
778 | "lowered return type of async fn is not OpaqueDef: {:?}", | |
779 | hir_ty | |
780 | ); | |
5099ac24 FG |
781 | }; |
782 | let opaque_ty = hir.item(id); | |
783 | if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { | |
784 | bounds: | |
785 | [ | |
786 | hir::GenericBound::LangItemTrait( | |
787 | hir::LangItem::Future, | |
788 | _, | |
789 | _, | |
790 | hir::GenericArgs { | |
791 | bindings: | |
792 | [ | |
793 | hir::TypeBinding { | |
794 | ident: Ident { name: sym::Output, .. }, | |
795 | kind: | |
796 | hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) }, | |
797 | .. | |
798 | }, | |
799 | ], | |
800 | .. | |
801 | }, | |
802 | ), | |
803 | ], | |
804 | .. | |
805 | }) = opaque_ty.kind | |
806 | { | |
807 | ty | |
808 | } else { | |
809 | span_bug!( | |
810 | hir_ty.span, | |
811 | "bounds from lowered return type of async fn did not match expected format: {:?}", | |
812 | opaque_ty | |
813 | ); | |
29967ef6 XL |
814 | } |
815 | } | |
816 | ||
923072b8 | 817 | #[tracing::instrument(level = "trace", skip(self))] |
48663c56 XL |
818 | fn give_name_if_anonymous_region_appears_in_yield_ty( |
819 | &self, | |
48663c56 | 820 | fr: RegionVid, |
48663c56 XL |
821 | ) -> Option<RegionName> { |
822 | // Note: generators from `async fn` yield `()`, so we don't have to | |
823 | // worry about them here. | |
dfeec247 | 824 | let yield_ty = self.regioncx.universal_regions().yield_ty?; |
04454e1e | 825 | debug!("give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}", yield_ty); |
48663c56 | 826 | |
dfeec247 | 827 | let tcx = self.infcx.tcx; |
48663c56 XL |
828 | |
829 | if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) { | |
830 | return None; | |
831 | } | |
832 | ||
5099ac24 | 833 | let mut highlight = RegionHighlightMode::new(tcx); |
dfeec247 | 834 | highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); |
1b1a35ee XL |
835 | let type_name = |
836 | self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; | |
48663c56 | 837 | |
29967ef6 | 838 | let yield_span = match tcx.hir().get(self.mir_hir_id()) { |
48663c56 | 839 | hir::Node::Expr(hir::Expr { |
064997fb | 840 | kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), |
923072b8 | 841 | .. |
064997fb | 842 | }) => tcx.sess.source_map().end_point(fn_decl_span), |
dfeec247 | 843 | _ => self.body.span, |
48663c56 XL |
844 | }; |
845 | ||
846 | debug!( | |
847 | "give_name_if_anonymous_region_appears_in_yield_ty: \ | |
848 | type_name = {:?}, yield_span = {:?}", | |
dfeec247 | 849 | yield_span, type_name, |
48663c56 XL |
850 | ); |
851 | ||
852 | Some(RegionName { | |
dfeec247 | 853 | name: self.synthesize_region_name(), |
48663c56 XL |
854 | source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name), |
855 | }) | |
856 | } | |
923072b8 FG |
857 | |
858 | fn give_name_if_anonymous_region_appears_in_impl_signature( | |
859 | &self, | |
860 | fr: RegionVid, | |
861 | ) -> Option<RegionName> { | |
862 | let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else { | |
863 | return None; | |
864 | }; | |
865 | if region.has_name() { | |
866 | return None; | |
867 | }; | |
868 | ||
869 | let tcx = self.infcx.tcx; | |
870 | let body_parent_did = tcx.opt_parent(self.mir_def_id().to_def_id())?; | |
871 | if tcx.parent(region.def_id) != body_parent_did | |
872 | || tcx.def_kind(body_parent_did) != DefKind::Impl | |
873 | { | |
874 | return None; | |
875 | } | |
876 | ||
877 | let mut found = false; | |
064997fb | 878 | tcx.fold_regions(tcx.type_of(body_parent_did), |r: ty::Region<'tcx>, _| { |
923072b8 FG |
879 | if *r == ty::ReEarlyBound(region) { |
880 | found = true; | |
881 | } | |
882 | r | |
883 | }); | |
884 | ||
885 | Some(RegionName { | |
886 | name: self.synthesize_region_name(), | |
887 | source: RegionNameSource::AnonRegionFromImplSignature( | |
888 | tcx.def_span(region.def_id), | |
889 | // FIXME(compiler-errors): Does this ever actually show up | |
890 | // anywhere other than the self type? I couldn't create an | |
891 | // example of a `'_` in the impl's trait being referenceable. | |
892 | if found { "self type" } else { "header" }, | |
893 | ), | |
894 | }) | |
895 | } | |
8faf50e0 | 896 | } |