]>
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}; | |
353b0b11 | 9 | use rustc_middle::ty::{self, RegionVid, Ty}; |
29967ef6 XL |
10 | use rustc_span::symbol::{kw, sym, Ident, Symbol}; |
11 | use rustc_span::{Span, DUMMY_SP}; | |
dfeec247 | 12 | |
353b0b11 | 13 | use crate::{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 | ||
9ffffee4 FG |
190 | impl rustc_errors::IntoDiagnosticArg for RegionName { |
191 | fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { | |
192 | self.to_string().into_diagnostic_arg() | |
193 | } | |
194 | } | |
195 | ||
dfeec247 | 196 | impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { |
923072b8 | 197 | pub(crate) fn mir_def_id(&self) -> hir::def_id::LocalDefId { |
064997fb | 198 | self.body.source.def_id().expect_local() |
29967ef6 XL |
199 | } |
200 | ||
923072b8 | 201 | pub(crate) fn mir_hir_id(&self) -> hir::HirId { |
29967ef6 XL |
202 | self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id()) |
203 | } | |
204 | ||
dfeec247 XL |
205 | /// Generate a synthetic region named `'N`, where `N` is the next value of the counter. Then, |
206 | /// increment the counter. | |
207 | /// | |
208 | /// This is _not_ idempotent. Call `give_region_a_name` when possible. | |
9c376795 | 209 | pub(crate) fn synthesize_region_name(&self) -> Symbol { |
dfeec247 | 210 | let c = self.next_region_name.replace_with(|counter| *counter + 1); |
9c376795 | 211 | Symbol::intern(&format!("'{c:?}")) |
dfeec247 XL |
212 | } |
213 | ||
8faf50e0 XL |
214 | /// Maps from an internal MIR region vid to something that we can |
215 | /// report to the user. In some cases, the region vids will map | |
216 | /// directly to lifetimes that the user has a name for (e.g., | |
217 | /// `'static`). But frequently they will not, in which case we | |
218 | /// have to find some way to identify the lifetime to the user. To | |
219 | /// that end, this function takes a "diagnostic" so that it can | |
220 | /// create auxiliary notes as needed. | |
221 | /// | |
dfeec247 XL |
222 | /// The names are memoized, so this is both cheap to recompute and idempotent. |
223 | /// | |
8faf50e0 XL |
224 | /// Example (function arguments): |
225 | /// | |
226 | /// Suppose we are trying to give a name to the lifetime of the | |
227 | /// reference `x`: | |
228 | /// | |
04454e1e | 229 | /// ```ignore (pseudo-rust) |
8faf50e0 XL |
230 | /// fn foo(x: &u32) { .. } |
231 | /// ``` | |
232 | /// | |
233 | /// This function would create a label like this: | |
234 | /// | |
ba9703b0 | 235 | /// ```text |
8faf50e0 XL |
236 | /// | fn foo(x: &u32) { .. } |
237 | /// ------- fully elaborated type of `x` is `&'1 u32` | |
238 | /// ``` | |
239 | /// | |
240 | /// and then return the name `'1` for us to use. | |
923072b8 | 241 | pub(crate) fn give_region_a_name(&self, fr: RegionVid) -> Option<RegionName> { |
dfeec247 XL |
242 | debug!( |
243 | "give_region_a_name(fr={:?}, counter={:?})", | |
244 | fr, | |
245 | self.next_region_name.try_borrow().unwrap() | |
246 | ); | |
8faf50e0 | 247 | |
dfeec247 | 248 | assert!(self.regioncx.universal_regions().is_universal_region(fr)); |
8faf50e0 | 249 | |
dfeec247 | 250 | if let Some(value) = self.region_names.try_borrow_mut().unwrap().get(&fr) { |
e1599b0c XL |
251 | return Some(value.clone()); |
252 | } | |
253 | ||
254 | let value = self | |
dfeec247 XL |
255 | .give_name_from_error_region(fr) |
256 | .or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr)) | |
257 | .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr)) | |
258 | .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr)) | |
923072b8 | 259 | .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr)) |
2b03887a FG |
260 | .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr)) |
261 | .or_else(|| self.give_name_if_anonymous_region_appears_in_arg_position_impl_trait(fr)); | |
b7449926 | 262 | |
487cf647 | 263 | if let Some(value) = &value { |
dfeec247 | 264 | self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone()); |
e1599b0c XL |
265 | } |
266 | ||
b7449926 XL |
267 | debug!("give_region_a_name: gave name {:?}", value); |
268 | value | |
8faf50e0 XL |
269 | } |
270 | ||
9fa01778 | 271 | /// Checks for the case where `fr` maps to something that the |
8faf50e0 XL |
272 | /// *user* has a name for. In that case, we'll be able to map |
273 | /// `fr` to a `Region<'tcx>`, and that region will be one of | |
274 | /// named variants. | |
f2b60f7d | 275 | #[instrument(level = "trace", skip(self))] |
dfeec247 | 276 | fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> { |
8faf50e0 | 277 | let error_region = self.to_error_region(fr)?; |
b7449926 | 278 | |
dfeec247 XL |
279 | let tcx = self.infcx.tcx; |
280 | ||
8faf50e0 | 281 | debug!("give_region_a_name: error_region = {:?}", error_region); |
5099ac24 | 282 | match *error_region { |
9ffffee4 FG |
283 | ty::ReEarlyBound(ebr) => ebr.has_name().then(|| { |
284 | let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP); | |
285 | RegionName { name: ebr.name, source: RegionNameSource::NamedEarlyBoundRegion(span) } | |
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 \ | |
9ffffee4 | 339 | can't escape the closure" |
5099ac24 FG |
340 | } |
341 | Some(ty::ClosureKind::FnMut) => { | |
342 | "closure implements `FnMut`, so references to captured variables \ | |
9ffffee4 | 343 | can't escape the closure" |
5099ac24 FG |
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 | ||
487cf647 | 357 | ty::BoundRegionKind::BrAnon(..) => None, |
8faf50e0 XL |
358 | }, |
359 | ||
9ffffee4 FG |
360 | ty::ReLateBound(..) |
361 | | ty::ReVar(..) | |
362 | | ty::RePlaceholder(..) | |
363 | | ty::ReErased | |
364 | | ty::ReError(_) => 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 | /// ``` | |
f2b60f7d | 376 | #[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` | |
9c376795 | 499 | (ty::Ref(region, referent_ty, _), hir::TyKind::Ref(_lifetime, referent_hir_ty)) => { |
353b0b11 | 500 | if region.as_var() == needle_fr { |
8faf50e0 | 501 | // Just grab the first character, the `&`. |
dfeec247 | 502 | let source_map = self.infcx.tcx.sess.source_map(); |
b7449926 | 503 | let ampersand_span = source_map.start_point(hir_ty.span); |
8faf50e0 | 504 | |
3dfed10e | 505 | return Some(RegionNameHighlight::MatchedHirTy(ampersand_span)); |
8faf50e0 XL |
506 | } |
507 | ||
508 | // Otherwise, let's descend into the referent types. | |
5099ac24 | 509 | search_stack.push((*referent_ty, &referent_hir_ty.ty)); |
8faf50e0 XL |
510 | } |
511 | ||
512 | // Match up something like `Foo<'1>` | |
513 | ( | |
b7449926 | 514 | ty::Adt(_adt_def, substs), |
8faf50e0 XL |
515 | hir::TyKind::Path(hir::QPath::Resolved(None, path)), |
516 | ) => { | |
48663c56 | 517 | match path.res { |
0bf4aa26 XL |
518 | // Type parameters of the type alias have no reason to |
519 | // be the same as those of the ADT. | |
520 | // FIXME: We should be able to do something similar to | |
521 | // match_adt_and_segment in this case. | |
48663c56 | 522 | Res::Def(DefKind::TyAlias, _) => (), |
dfeec247 XL |
523 | _ => { |
524 | if let Some(last_segment) = path.segments.last() { | |
3dfed10e | 525 | if let Some(highlight) = self.match_adt_and_segment( |
dfeec247 XL |
526 | substs, |
527 | needle_fr, | |
528 | last_segment, | |
529 | search_stack, | |
530 | ) { | |
3dfed10e | 531 | return Some(highlight); |
dfeec247 | 532 | } |
0bf4aa26 | 533 | } |
8faf50e0 XL |
534 | } |
535 | } | |
536 | } | |
537 | ||
538 | // The following cases don't have lifetimes, so we | |
539 | // just worry about trying to match up the rustc type | |
540 | // with the HIR types: | |
5e7ed085 FG |
541 | (&ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => { |
542 | search_stack.extend(iter::zip(elem_tys, *elem_hir_tys)); | |
8faf50e0 XL |
543 | } |
544 | ||
b7449926 XL |
545 | (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty)) |
546 | | (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => { | |
5099ac24 | 547 | search_stack.push((*elem_ty, elem_hir_ty)); |
8faf50e0 XL |
548 | } |
549 | ||
b7449926 | 550 | (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => { |
8faf50e0 XL |
551 | search_stack.push((mut_ty.ty, &mut_hir_ty.ty)); |
552 | } | |
553 | ||
554 | _ => { | |
555 | // FIXME there are other cases that we could trace | |
556 | } | |
557 | } | |
558 | } | |
559 | ||
ba9703b0 | 560 | None |
8faf50e0 XL |
561 | } |
562 | ||
563 | /// We've found an enum/struct/union type with the substitutions | |
564 | /// `substs` and -- in the HIR -- a path type with the final | |
565 | /// segment `last_segment`. Try to find a `'_` to highlight in | |
566 | /// the generic args (or, if not, to produce new zipped pairs of | |
567 | /// types+hir to search through). | |
568 | fn match_adt_and_segment<'hir>( | |
569 | &self, | |
532ac7d7 | 570 | substs: SubstsRef<'tcx>, |
8faf50e0 | 571 | needle_fr: RegionVid, |
dfeec247 XL |
572 | last_segment: &'hir hir::PathSegment<'hir>, |
573 | search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>, | |
3dfed10e | 574 | ) -> Option<RegionNameHighlight> { |
8faf50e0 XL |
575 | // Did the user give explicit arguments? (e.g., `Foo<..>`) |
576 | let args = last_segment.args.as_ref()?; | |
e1599b0c XL |
577 | let lifetime = |
578 | self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; | |
487cf647 FG |
579 | if lifetime.is_anonymous() { |
580 | None | |
581 | } else { | |
582 | Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime.ident.span)) | |
8faf50e0 XL |
583 | } |
584 | } | |
585 | ||
586 | /// We've found an enum/struct/union type with the substitutions | |
587 | /// `substs` and -- in the HIR -- a path with the generic | |
588 | /// arguments `args`. If `needle_fr` appears in the args, return | |
589 | /// the `hir::Lifetime` that corresponds to it. If not, push onto | |
590 | /// `search_stack` the types+hir to search through. | |
591 | fn try_match_adt_and_generic_args<'hir>( | |
592 | &self, | |
532ac7d7 | 593 | substs: SubstsRef<'tcx>, |
8faf50e0 | 594 | needle_fr: RegionVid, |
dfeec247 XL |
595 | args: &'hir hir::GenericArgs<'hir>, |
596 | search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>, | |
8faf50e0 | 597 | ) -> Option<&'hir hir::Lifetime> { |
cdc7bbd5 | 598 | for (kind, hir_arg) in iter::zip(substs, args.args) { |
8faf50e0 | 599 | match (kind.unpack(), hir_arg) { |
e74abb32 | 600 | (GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => { |
353b0b11 | 601 | if r.as_var() == needle_fr { |
8faf50e0 XL |
602 | return Some(lt); |
603 | } | |
604 | } | |
605 | ||
e74abb32 | 606 | (GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => { |
8faf50e0 XL |
607 | search_stack.push((ty, hir_ty)); |
608 | } | |
609 | ||
e74abb32 | 610 | (GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => { |
532ac7d7 XL |
611 | // Lifetimes cannot be found in consts, so we don't need |
612 | // to search anything here. | |
613 | } | |
614 | ||
ba9703b0 XL |
615 | ( |
616 | GenericArgKind::Lifetime(_) | |
617 | | GenericArgKind::Type(_) | |
618 | | GenericArgKind::Const(_), | |
619 | _, | |
620 | ) => { | |
6a06907d XL |
621 | // HIR lowering sometimes doesn't catch this in erroneous |
622 | // programs, so we need to use delay_span_bug here. See #82126. | |
623 | self.infcx.tcx.sess.delay_span_bug( | |
8faf50e0 | 624 | hir_arg.span(), |
49aad941 | 625 | format!("unmatched subst and hir arg: found {kind:?} vs {hir_arg:?}"), |
8faf50e0 XL |
626 | ); |
627 | } | |
628 | } | |
629 | } | |
630 | ||
631 | None | |
632 | } | |
633 | ||
9fa01778 | 634 | /// Finds a closure upvar that contains `fr` and label it with a |
8faf50e0 XL |
635 | /// fully elaborated type, returning something like `'1`. Result |
636 | /// looks like: | |
637 | /// | |
ba9703b0 | 638 | /// ```text |
8faf50e0 XL |
639 | /// | let x = Some(&22); |
640 | /// - fully elaborated type of `x` is `Option<&'1 u32>` | |
641 | /// ``` | |
f2b60f7d | 642 | #[instrument(level = "trace", skip(self))] |
dfeec247 XL |
643 | fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> { |
644 | let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?; | |
645 | let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( | |
646 | self.infcx.tcx, | |
647 | &self.upvars, | |
648 | upvar_index, | |
649 | ); | |
650 | let region_name = self.synthesize_region_name(); | |
8faf50e0 | 651 | |
0bf4aa26 XL |
652 | Some(RegionName { |
653 | name: region_name, | |
064997fb | 654 | source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), |
0bf4aa26 | 655 | }) |
8faf50e0 XL |
656 | } |
657 | ||
9fa01778 | 658 | /// Checks for arguments appearing in the (closure) return type. It |
8faf50e0 XL |
659 | /// must be a closure since, in a free fn, such an argument would |
660 | /// have to either also appear in an argument (if using elision) | |
661 | /// or be early bound (named, not in argument). | |
f2b60f7d | 662 | #[instrument(level = "trace", skip(self))] |
dfeec247 XL |
663 | fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> { |
664 | let tcx = self.infcx.tcx; | |
29967ef6 | 665 | let hir = tcx.hir(); |
b7449926 | 666 | |
dfeec247 XL |
667 | let return_ty = self.regioncx.universal_regions().unnormalized_output_ty; |
668 | debug!("give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty); | |
353b0b11 | 669 | if !tcx.any_free_region_meets(&return_ty, |r| r.as_var() == fr) { |
8faf50e0 XL |
670 | return None; |
671 | } | |
672 | ||
29967ef6 | 673 | let mir_hir_id = self.mir_hir_id(); |
b7449926 | 674 | |
29967ef6 | 675 | let (return_span, mir_description, hir_ty) = match hir.get(mir_hir_id) { |
a1dfa0c6 | 676 | hir::Node::Expr(hir::Expr { |
064997fb | 677 | kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, .. }), |
a1dfa0c6 | 678 | .. |
29967ef6 | 679 | }) => { |
923072b8 | 680 | let (mut span, mut hir_ty) = match fn_decl.output { |
29967ef6 | 681 | hir::FnRetTy::DefaultReturn(_) => { |
064997fb | 682 | (tcx.sess.source_map().end_point(fn_decl_span), None) |
29967ef6 | 683 | } |
923072b8 | 684 | hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)), |
29967ef6 | 685 | }; |
064997fb | 686 | let mir_description = match hir.body(body).generator_kind { |
29967ef6 XL |
687 | Some(hir::GeneratorKind::Async(gen)) => match gen { |
688 | hir::AsyncGeneratorKind::Block => " of async block", | |
689 | hir::AsyncGeneratorKind::Closure => " of async closure", | |
690 | hir::AsyncGeneratorKind::Fn => { | |
2b03887a FG |
691 | let parent_item = |
692 | hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id); | |
29967ef6 XL |
693 | let output = &parent_item |
694 | .fn_decl() | |
695 | .expect("generator lowered from async fn should be in fn") | |
696 | .output; | |
697 | span = output.span(); | |
698 | if let hir::FnRetTy::Return(ret) = output { | |
699 | hir_ty = Some(self.get_future_inner_return_ty(*ret)); | |
700 | } | |
701 | " of async function" | |
702 | } | |
703 | }, | |
704 | Some(hir::GeneratorKind::Gen) => " of generator", | |
705 | None => " of closure", | |
706 | }; | |
707 | (span, mir_description, hir_ty) | |
708 | } | |
709 | node => match node.fn_decl() { | |
710 | Some(fn_decl) => { | |
711 | let hir_ty = match fn_decl.output { | |
712 | hir::FnRetTy::DefaultReturn(_) => None, | |
713 | hir::FnRetTy::Return(ty) => Some(ty), | |
714 | }; | |
715 | (fn_decl.output.span(), "", hir_ty) | |
716 | } | |
717 | None => (self.body.span, "", None), | |
718 | }, | |
a1dfa0c6 | 719 | }; |
b7449926 | 720 | |
29967ef6 XL |
721 | let highlight = hir_ty |
722 | .and_then(|hir_ty| self.highlight_if_we_can_match_hir_ty(fr, return_ty, hir_ty)) | |
723 | .unwrap_or_else(|| { | |
724 | // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to | |
725 | // the anonymous region. If it succeeds, the `synthesize_region_name` call below | |
726 | // will increment the counter, "reserving" the number we just used. | |
727 | let counter = *self.next_region_name.try_borrow().unwrap(); | |
728 | self.highlight_if_we_cannot_match_hir_ty(fr, return_ty, return_span, counter) | |
729 | }); | |
730 | ||
0bf4aa26 | 731 | Some(RegionName { |
dfeec247 | 732 | name: self.synthesize_region_name(), |
064997fb | 733 | source: RegionNameSource::AnonRegionFromOutput(highlight, mir_description), |
0bf4aa26 | 734 | }) |
8faf50e0 XL |
735 | } |
736 | ||
29967ef6 XL |
737 | /// From the [`hir::Ty`] of an async function's lowered return type, |
738 | /// retrieve the `hir::Ty` representing the type the user originally wrote. | |
739 | /// | |
740 | /// e.g. given the function: | |
741 | /// | |
742 | /// ``` | |
04454e1e | 743 | /// async fn foo() -> i32 { 2 } |
29967ef6 XL |
744 | /// ``` |
745 | /// | |
746 | /// this function, given the lowered return type of `foo`, an [`OpaqueDef`] that implements `Future<Output=i32>`, | |
747 | /// returns the `i32`. | |
748 | /// | |
749 | /// [`OpaqueDef`]: hir::TyKind::OpaqueDef | |
750 | fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { | |
751 | let hir = self.infcx.tcx.hir(); | |
752 | ||
f2b60f7d | 753 | let hir::TyKind::OpaqueDef(id, _, _) = hir_ty.kind else { |
29967ef6 XL |
754 | span_bug!( |
755 | hir_ty.span, | |
756 | "lowered return type of async fn is not OpaqueDef: {:?}", | |
757 | hir_ty | |
758 | ); | |
5099ac24 FG |
759 | }; |
760 | let opaque_ty = hir.item(id); | |
761 | if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { | |
762 | bounds: | |
763 | [ | |
764 | hir::GenericBound::LangItemTrait( | |
765 | hir::LangItem::Future, | |
766 | _, | |
767 | _, | |
768 | hir::GenericArgs { | |
769 | bindings: | |
770 | [ | |
771 | hir::TypeBinding { | |
772 | ident: Ident { name: sym::Output, .. }, | |
773 | kind: | |
774 | hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) }, | |
775 | .. | |
776 | }, | |
777 | ], | |
778 | .. | |
779 | }, | |
780 | ), | |
781 | ], | |
782 | .. | |
783 | }) = opaque_ty.kind | |
784 | { | |
785 | ty | |
786 | } else { | |
787 | span_bug!( | |
788 | hir_ty.span, | |
9c376795 | 789 | "bounds from lowered return type of async fn did not match expected format: {opaque_ty:?}", |
5099ac24 | 790 | ); |
29967ef6 XL |
791 | } |
792 | } | |
793 | ||
f2b60f7d | 794 | #[instrument(level = "trace", skip(self))] |
48663c56 XL |
795 | fn give_name_if_anonymous_region_appears_in_yield_ty( |
796 | &self, | |
48663c56 | 797 | fr: RegionVid, |
48663c56 XL |
798 | ) -> Option<RegionName> { |
799 | // Note: generators from `async fn` yield `()`, so we don't have to | |
800 | // worry about them here. | |
dfeec247 | 801 | let yield_ty = self.regioncx.universal_regions().yield_ty?; |
04454e1e | 802 | debug!("give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}", yield_ty); |
48663c56 | 803 | |
dfeec247 | 804 | let tcx = self.infcx.tcx; |
48663c56 | 805 | |
353b0b11 | 806 | if !tcx.any_free_region_meets(&yield_ty, |r| r.as_var() == fr) { |
48663c56 XL |
807 | return None; |
808 | } | |
809 | ||
5099ac24 | 810 | let mut highlight = RegionHighlightMode::new(tcx); |
dfeec247 | 811 | highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); |
1b1a35ee XL |
812 | let type_name = |
813 | self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; | |
48663c56 | 814 | |
29967ef6 | 815 | let yield_span = match tcx.hir().get(self.mir_hir_id()) { |
48663c56 | 816 | hir::Node::Expr(hir::Expr { |
064997fb | 817 | kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), |
923072b8 | 818 | .. |
064997fb | 819 | }) => tcx.sess.source_map().end_point(fn_decl_span), |
dfeec247 | 820 | _ => self.body.span, |
48663c56 XL |
821 | }; |
822 | ||
823 | debug!( | |
824 | "give_name_if_anonymous_region_appears_in_yield_ty: \ | |
825 | type_name = {:?}, yield_span = {:?}", | |
dfeec247 | 826 | yield_span, type_name, |
48663c56 XL |
827 | ); |
828 | ||
829 | Some(RegionName { | |
dfeec247 | 830 | name: self.synthesize_region_name(), |
48663c56 XL |
831 | source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name), |
832 | }) | |
833 | } | |
923072b8 FG |
834 | |
835 | fn give_name_if_anonymous_region_appears_in_impl_signature( | |
836 | &self, | |
837 | fr: RegionVid, | |
838 | ) -> Option<RegionName> { | |
839 | let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else { | |
840 | return None; | |
841 | }; | |
842 | if region.has_name() { | |
843 | return None; | |
844 | }; | |
845 | ||
846 | let tcx = self.infcx.tcx; | |
2b03887a | 847 | let region_parent = tcx.parent(region.def_id); |
9ffffee4 | 848 | let DefKind::Impl { .. } = tcx.def_kind(region_parent) else { |
923072b8 | 849 | return None; |
9ffffee4 | 850 | }; |
923072b8 | 851 | |
9ffffee4 FG |
852 | let found = tcx.any_free_region_meets(&tcx.type_of(region_parent).subst_identity(), |r| { |
853 | *r == ty::ReEarlyBound(region) | |
854 | }); | |
923072b8 FG |
855 | |
856 | Some(RegionName { | |
857 | name: self.synthesize_region_name(), | |
858 | source: RegionNameSource::AnonRegionFromImplSignature( | |
859 | tcx.def_span(region.def_id), | |
860 | // FIXME(compiler-errors): Does this ever actually show up | |
861 | // anywhere other than the self type? I couldn't create an | |
862 | // example of a `'_` in the impl's trait being referenceable. | |
863 | if found { "self type" } else { "header" }, | |
864 | ), | |
865 | }) | |
866 | } | |
2b03887a FG |
867 | |
868 | fn give_name_if_anonymous_region_appears_in_arg_position_impl_trait( | |
869 | &self, | |
870 | fr: RegionVid, | |
871 | ) -> Option<RegionName> { | |
872 | let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else { | |
873 | return None; | |
874 | }; | |
875 | if region.has_name() { | |
876 | return None; | |
877 | }; | |
878 | ||
879 | let predicates = self | |
880 | .infcx | |
881 | .tcx | |
882 | .predicates_of(self.body.source.def_id()) | |
883 | .instantiate_identity(self.infcx.tcx) | |
884 | .predicates; | |
885 | ||
886 | if let Some(upvar_index) = self | |
887 | .regioncx | |
888 | .universal_regions() | |
889 | .defining_ty | |
890 | .upvar_tys() | |
891 | .position(|ty| self.any_param_predicate_mentions(&predicates, ty, region)) | |
892 | { | |
893 | let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( | |
894 | self.infcx.tcx, | |
895 | &self.upvars, | |
896 | upvar_index, | |
897 | ); | |
898 | let region_name = self.synthesize_region_name(); | |
899 | ||
900 | Some(RegionName { | |
901 | name: region_name, | |
902 | source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), | |
903 | }) | |
904 | } else if let Some(arg_index) = self | |
905 | .regioncx | |
906 | .universal_regions() | |
907 | .unnormalized_input_tys | |
908 | .iter() | |
909 | .position(|ty| self.any_param_predicate_mentions(&predicates, *ty, region)) | |
910 | { | |
911 | let (arg_name, arg_span) = self.regioncx.get_argument_name_and_span_for_region( | |
912 | self.body, | |
913 | &self.local_names, | |
914 | arg_index, | |
915 | ); | |
916 | let region_name = self.synthesize_region_name(); | |
917 | ||
918 | Some(RegionName { | |
919 | name: region_name, | |
920 | source: RegionNameSource::AnonRegionFromArgument( | |
921 | RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?.to_string()), | |
922 | ), | |
923 | }) | |
924 | } else { | |
925 | None | |
926 | } | |
927 | } | |
928 | ||
929 | fn any_param_predicate_mentions( | |
930 | &self, | |
931 | predicates: &[ty::Predicate<'tcx>], | |
932 | ty: Ty<'tcx>, | |
933 | region: ty::EarlyBoundRegion, | |
934 | ) -> bool { | |
935 | let tcx = self.infcx.tcx; | |
936 | ty.walk().any(|arg| { | |
937 | if let ty::GenericArgKind::Type(ty) = arg.unpack() | |
938 | && let ty::Param(_) = ty.kind() | |
939 | { | |
940 | predicates.iter().any(|pred| { | |
941 | match pred.kind().skip_binder() { | |
487cf647 FG |
942 | ty::PredicateKind::Clause(ty::Clause::Trait(data)) if data.self_ty() == ty => {} |
943 | ty::PredicateKind::Clause(ty::Clause::Projection(data)) if data.projection_ty.self_ty() == ty => {} | |
2b03887a FG |
944 | _ => return false, |
945 | } | |
946 | tcx.any_free_region_meets(pred, |r| { | |
947 | *r == ty::ReEarlyBound(region) | |
948 | }) | |
949 | }) | |
950 | } else { | |
951 | false | |
952 | } | |
953 | }) | |
954 | } | |
8faf50e0 | 955 | } |