]>
Commit | Line | Data |
---|---|---|
064997fb | 1 | //! Resolution of early vs late bound lifetimes. |
dfeec247 | 2 | //! |
064997fb FG |
3 | //! Name resolution for lifetimes is performed on the AST and embedded into HIR. From this |
4 | //! information, typechecking needs to transform the lifetime parameters into bound lifetimes. | |
5 | //! Lifetimes can be early-bound or late-bound. Construction of typechecking terms needs to visit | |
6 | //! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file | |
7 | //! is also responsible for assigning their semantics to implicit lifetimes in trait objects. | |
dfeec247 | 8 | |
74b04a01 | 9 | use rustc_ast::walk_list; |
923072b8 FG |
10 | use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; |
11 | use rustc_errors::struct_span_err; | |
dfeec247 XL |
12 | use rustc_hir as hir; |
13 | use rustc_hir::def::{DefKind, Res}; | |
f2b60f7d | 14 | use rustc_hir::def_id::LocalDefId; |
5099ac24 | 15 | use rustc_hir::intravisit::{self, Visitor}; |
064997fb FG |
16 | use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node}; |
17 | use rustc_middle::bug; | |
ba9703b0 | 18 | use rustc_middle::hir::map::Map; |
5099ac24 | 19 | use rustc_middle::hir::nested_filter; |
ba9703b0 | 20 | use rustc_middle::middle::resolve_lifetime::*; |
f2b60f7d | 21 | use rustc_middle::ty::{self, DefIdTree, TyCtxt}; |
17df50a5 | 22 | use rustc_span::def_id::DefId; |
064997fb | 23 | use rustc_span::symbol::{sym, Ident}; |
dfeec247 | 24 | use rustc_span::Span; |
cdc7bbd5 | 25 | use std::fmt; |
dfeec247 | 26 | |
dfeec247 | 27 | trait RegionExt { |
f2b60f7d | 28 | fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region); |
dfeec247 | 29 | |
923072b8 | 30 | fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region); |
dfeec247 | 31 | |
dfeec247 XL |
32 | fn id(&self) -> Option<DefId>; |
33 | ||
34 | fn shifted(self, amount: u32) -> Region; | |
dfeec247 XL |
35 | } |
36 | ||
37 | impl RegionExt for Region { | |
f2b60f7d | 38 | fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) { |
dfeec247 | 39 | let def_id = hir_map.local_def_id(param.hir_id); |
f2b60f7d FG |
40 | debug!("Region::early: def_id={:?}", def_id); |
41 | (def_id, Region::EarlyBound(def_id.to_def_id())) | |
dfeec247 XL |
42 | } |
43 | ||
923072b8 | 44 | fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) { |
dfeec247 XL |
45 | let depth = ty::INNERMOST; |
46 | let def_id = hir_map.local_def_id(param.hir_id); | |
dfeec247 | 47 | debug!( |
5e7ed085 FG |
48 | "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}", |
49 | idx, param, depth, def_id, | |
dfeec247 | 50 | ); |
923072b8 | 51 | (def_id, Region::LateBound(depth, idx, def_id.to_def_id())) |
dfeec247 XL |
52 | } |
53 | ||
dfeec247 XL |
54 | fn id(&self) -> Option<DefId> { |
55 | match *self { | |
064997fb | 56 | Region::Static => None, |
dfeec247 | 57 | |
f2b60f7d | 58 | Region::EarlyBound(id) | Region::LateBound(_, _, id) | Region::Free(_, id) => Some(id), |
dfeec247 XL |
59 | } |
60 | } | |
61 | ||
62 | fn shifted(self, amount: u32) -> Region { | |
63 | match self { | |
5e7ed085 FG |
64 | Region::LateBound(debruijn, idx, id) => { |
65 | Region::LateBound(debruijn.shifted_in(amount), idx, id) | |
dfeec247 | 66 | } |
dfeec247 XL |
67 | _ => self, |
68 | } | |
69 | } | |
dfeec247 XL |
70 | } |
71 | ||
72 | /// Maps the id of each lifetime reference to the lifetime decl | |
73 | /// that it corresponds to. | |
74 | /// | |
75 | /// FIXME. This struct gets converted to a `ResolveLifetimes` for | |
ba9703b0 | 76 | /// actual use. It has the same data, but indexed by `LocalDefId`. This |
dfeec247 | 77 | /// is silly. |
cdc7bbd5 | 78 | #[derive(Debug, Default)] |
dfeec247 XL |
79 | struct NamedRegionMap { |
80 | // maps from every use of a named (not anonymous) lifetime to a | |
81 | // `Region` describing how that region is bound | |
82 | defs: HirIdMap<Region>, | |
83 | ||
cdc7bbd5 XL |
84 | // Maps relevant hir items to the bound vars on them. These include: |
85 | // - function defs | |
86 | // - function pointers | |
87 | // - closures | |
88 | // - trait refs | |
89 | // - bound types (like `T` in `for<'a> T<'a>: Foo`) | |
90 | late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>, | |
dfeec247 XL |
91 | } |
92 | ||
2b03887a FG |
93 | struct LifetimeContext<'a, 'tcx> { |
94 | tcx: TyCtxt<'tcx>, | |
dfeec247 XL |
95 | map: &'a mut NamedRegionMap, |
96 | scope: ScopeRef<'a>, | |
97 | ||
cdc7bbd5 XL |
98 | /// Indicates that we only care about the definition of a trait. This should |
99 | /// be false if the `Item` we are resolving lifetimes for is not a trait or | |
100 | /// we eventually need lifetimes resolve for trait items. | |
101 | trait_definition_only: bool, | |
dfeec247 XL |
102 | } |
103 | ||
104 | #[derive(Debug)] | |
105 | enum Scope<'a> { | |
106 | /// Declares lifetimes, and each can be early-bound or late-bound. | |
107 | /// The `DebruijnIndex` of late-bound lifetimes starts at `1` and | |
108 | /// it should be shifted by the number of `Binder`s in between the | |
109 | /// declaration `Binder` and the location it's referenced from. | |
110 | Binder { | |
17df50a5 XL |
111 | /// We use an IndexMap here because we want these lifetimes in order |
112 | /// for diagnostics. | |
923072b8 | 113 | lifetimes: FxIndexMap<LocalDefId, Region>, |
dfeec247 | 114 | |
cdc7bbd5 XL |
115 | scope_type: BinderScopeType, |
116 | ||
117 | /// The late bound vars for a given item are stored by `HirId` to be | |
118 | /// queried later. However, if we enter an elision scope, we have to | |
119 | /// later append the elided bound vars to the list and need to know what | |
120 | /// to append to. | |
121 | hir_id: hir::HirId, | |
122 | ||
dfeec247 | 123 | s: ScopeRef<'a>, |
5e7ed085 | 124 | |
04454e1e FG |
125 | /// If this binder comes from a where clause, specify how it was created. |
126 | /// This is used to diagnose inaccessible lifetimes in APIT: | |
127 | /// ```ignore (illustrative) | |
128 | /// fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {} | |
129 | /// ``` | |
130 | where_bound_origin: Option<hir::PredicateOrigin>, | |
dfeec247 XL |
131 | }, |
132 | ||
133 | /// Lifetimes introduced by a fn are scoped to the call-site for that fn, | |
134 | /// if this is a fn body, otherwise the original definitions are used. | |
135 | /// Unspecified lifetimes are inferred, unless an elision scope is nested, | |
136 | /// e.g., `(&T, fn(&T) -> &T);` becomes `(&'_ T, for<'a> fn(&'a T) -> &'a T)`. | |
137 | Body { | |
138 | id: hir::BodyId, | |
139 | s: ScopeRef<'a>, | |
140 | }, | |
141 | ||
142 | /// A scope which either determines unspecified lifetimes or errors | |
064997fb | 143 | /// on them (e.g., due to ambiguity). |
dfeec247 | 144 | Elision { |
dfeec247 XL |
145 | s: ScopeRef<'a>, |
146 | }, | |
147 | ||
148 | /// Use a specific lifetime (if `Some`) or leave it unset (to be | |
149 | /// inferred in a function body or potentially error outside one), | |
150 | /// for the default choice of lifetime in a trait object type. | |
151 | ObjectLifetimeDefault { | |
152 | lifetime: Option<Region>, | |
153 | s: ScopeRef<'a>, | |
154 | }, | |
155 | ||
5e7ed085 | 156 | /// When we have nested trait refs, we concatenate late bound vars for inner |
cdc7bbd5 XL |
157 | /// trait refs from outer ones. But we also need to include any HRTB |
158 | /// lifetimes encountered when identifying the trait that an associated type | |
159 | /// is declared on. | |
160 | Supertrait { | |
161 | lifetimes: Vec<ty::BoundVariableKind>, | |
162 | s: ScopeRef<'a>, | |
163 | }, | |
164 | ||
165 | TraitRefBoundary { | |
166 | s: ScopeRef<'a>, | |
167 | }, | |
168 | ||
dfeec247 XL |
169 | Root, |
170 | } | |
171 | ||
cdc7bbd5 XL |
172 | #[derive(Copy, Clone, Debug)] |
173 | enum BinderScopeType { | |
174 | /// Any non-concatenating binder scopes. | |
175 | Normal, | |
176 | /// Within a syntactic trait ref, there may be multiple poly trait refs that | |
5e7ed085 FG |
177 | /// are nested (under the `associated_type_bounds` feature). The binders of |
178 | /// the inner poly trait refs are extended from the outer poly trait refs | |
cdc7bbd5 XL |
179 | /// and don't increase the late bound depth. If you had |
180 | /// `T: for<'a> Foo<Bar: for<'b> Baz<'a, 'b>>`, then the `for<'b>` scope | |
181 | /// would be `Concatenating`. This also used in trait refs in where clauses | |
182 | /// where we have two binders `for<> T: for<> Foo` (I've intentionally left | |
183 | /// out any lifetimes because they aren't needed to show the two scopes). | |
184 | /// The inner `for<>` has a scope of `Concatenating`. | |
185 | Concatenating, | |
186 | } | |
187 | ||
188 | // A helper struct for debugging scopes without printing parent scopes | |
189 | struct TruncatedScopeDebug<'a>(&'a Scope<'a>); | |
190 | ||
191 | impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { | |
192 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
193 | match self.0 { | |
f2b60f7d | 194 | Scope::Binder { lifetimes, scope_type, hir_id, where_bound_origin, s: _ } => f |
cdc7bbd5 XL |
195 | .debug_struct("Binder") |
196 | .field("lifetimes", lifetimes) | |
cdc7bbd5 XL |
197 | .field("scope_type", scope_type) |
198 | .field("hir_id", hir_id) | |
04454e1e FG |
199 | .field("where_bound_origin", where_bound_origin) |
200 | .field("s", &"..") | |
cdc7bbd5 XL |
201 | .finish(), |
202 | Scope::Body { id, s: _ } => { | |
203 | f.debug_struct("Body").field("id", id).field("s", &"..").finish() | |
204 | } | |
064997fb | 205 | Scope::Elision { s: _ } => f.debug_struct("Elision").field("s", &"..").finish(), |
cdc7bbd5 XL |
206 | Scope::ObjectLifetimeDefault { lifetime, s: _ } => f |
207 | .debug_struct("ObjectLifetimeDefault") | |
208 | .field("lifetime", lifetime) | |
209 | .field("s", &"..") | |
210 | .finish(), | |
211 | Scope::Supertrait { lifetimes, s: _ } => f | |
212 | .debug_struct("Supertrait") | |
213 | .field("lifetimes", lifetimes) | |
214 | .field("s", &"..") | |
215 | .finish(), | |
216 | Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(), | |
217 | Scope::Root => f.debug_struct("Root").finish(), | |
218 | } | |
219 | } | |
220 | } | |
221 | ||
dfeec247 XL |
222 | type ScopeRef<'a> = &'a Scope<'a>; |
223 | ||
224 | const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; | |
225 | ||
2b03887a | 226 | pub(crate) fn provide(providers: &mut ty::query::Providers) { |
dfeec247 | 227 | *providers = ty::query::Providers { |
cdc7bbd5 | 228 | resolve_lifetimes_trait_definition, |
dfeec247 XL |
229 | resolve_lifetimes, |
230 | ||
cdc7bbd5 | 231 | named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id), |
5869c6ff | 232 | is_late_bound_map, |
f2b60f7d | 233 | object_lifetime_default, |
cdc7bbd5 | 234 | late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id), |
dfeec247 XL |
235 | |
236 | ..*providers | |
237 | }; | |
dfeec247 XL |
238 | } |
239 | ||
cdc7bbd5 XL |
240 | /// Like `resolve_lifetimes`, but does not resolve lifetimes for trait items. |
241 | /// Also does not generate any diagnostics. | |
242 | /// | |
243 | /// This is ultimately a subset of the `resolve_lifetimes` work. It effectively | |
244 | /// resolves lifetimes only within the trait "header" -- that is, the trait | |
245 | /// and supertrait list. In contrast, `resolve_lifetimes` resolves all the | |
246 | /// lifetimes within the trait and its items. There is room to refactor this, | |
247 | /// for example to resolve lifetimes for each trait item in separate queries, | |
248 | /// but it's convenient to do the entire trait at once because the lifetimes | |
249 | /// from the trait definition are in scope within the trait items as well. | |
250 | /// | |
251 | /// The reason for this separate call is to resolve what would otherwise | |
252 | /// be a cycle. Consider this example: | |
253 | /// | |
04454e1e | 254 | /// ```ignore UNSOLVED (maybe @jackh726 knows what lifetime parameter to give Sub) |
cdc7bbd5 XL |
255 | /// trait Base<'a> { |
256 | /// type BaseItem; | |
257 | /// } | |
258 | /// trait Sub<'b>: for<'a> Base<'a> { | |
259 | /// type SubItem: Sub<BaseItem = &'b u32>; | |
260 | /// } | |
261 | /// ``` | |
262 | /// | |
263 | /// When we resolve `Sub` and all its items, we also have to resolve `Sub<BaseItem = &'b u32>`. | |
264 | /// To figure out the index of `'b`, we have to know about the supertraits | |
265 | /// of `Sub` so that we can determine that the `for<'a>` will be in scope. | |
266 | /// (This is because we -- currently at least -- flatten all the late-bound | |
267 | /// lifetimes into a single binder.) This requires us to resolve the | |
268 | /// *trait definition* of `Sub`; basically just enough lifetime information | |
269 | /// to look at the supertraits. | |
f2b60f7d | 270 | #[instrument(level = "debug", skip(tcx))] |
cdc7bbd5 XL |
271 | fn resolve_lifetimes_trait_definition( |
272 | tcx: TyCtxt<'_>, | |
273 | local_def_id: LocalDefId, | |
274 | ) -> ResolveLifetimes { | |
923072b8 | 275 | convert_named_region_map(do_resolve(tcx, local_def_id, true)) |
cdc7bbd5 | 276 | } |
dfeec247 | 277 | |
cdc7bbd5 XL |
278 | /// Computes the `ResolveLifetimes` map that contains data for an entire `Item`. |
279 | /// You should not read the result of this query directly, but rather use | |
280 | /// `named_region_map`, `is_late_bound_map`, etc. | |
f2b60f7d | 281 | #[instrument(level = "debug", skip(tcx))] |
cdc7bbd5 | 282 | fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes { |
923072b8 | 283 | convert_named_region_map(do_resolve(tcx, local_def_id, false)) |
cdc7bbd5 XL |
284 | } |
285 | ||
286 | fn do_resolve( | |
287 | tcx: TyCtxt<'_>, | |
288 | local_def_id: LocalDefId, | |
289 | trait_definition_only: bool, | |
17df50a5 | 290 | ) -> NamedRegionMap { |
a2a8927a | 291 | let item = tcx.hir().expect_item(local_def_id); |
923072b8 FG |
292 | let mut named_region_map = |
293 | NamedRegionMap { defs: Default::default(), late_bound_vars: Default::default() }; | |
cdc7bbd5 XL |
294 | let mut visitor = LifetimeContext { |
295 | tcx, | |
296 | map: &mut named_region_map, | |
297 | scope: ROOT_SCOPE, | |
cdc7bbd5 | 298 | trait_definition_only, |
cdc7bbd5 XL |
299 | }; |
300 | visitor.visit_item(item); | |
dfeec247 | 301 | |
17df50a5 XL |
302 | named_region_map |
303 | } | |
304 | ||
923072b8 | 305 | fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetimes { |
dfeec247 XL |
306 | let mut rl = ResolveLifetimes::default(); |
307 | ||
308 | for (hir_id, v) in named_region_map.defs { | |
ba9703b0 | 309 | let map = rl.defs.entry(hir_id.owner).or_default(); |
dfeec247 XL |
310 | map.insert(hir_id.local_id, v); |
311 | } | |
cdc7bbd5 XL |
312 | for (hir_id, v) in named_region_map.late_bound_vars { |
313 | let map = rl.late_bound_vars.entry(hir_id.owner).or_default(); | |
dfeec247 XL |
314 | map.insert(hir_id.local_id, v); |
315 | } | |
316 | ||
cdc7bbd5 | 317 | debug!(?rl.defs); |
2b03887a | 318 | debug!(?rl.late_bound_vars); |
f9f354fc | 319 | rl |
dfeec247 XL |
320 | } |
321 | ||
cdc7bbd5 XL |
322 | /// Given `any` owner (structs, traits, trait methods, etc.), does lifetime resolution. |
323 | /// There are two important things this does. | |
324 | /// First, we have to resolve lifetimes for | |
325 | /// the entire *`Item`* that contains this owner, because that's the largest "scope" | |
326 | /// where we can have relevant lifetimes. | |
327 | /// Second, if we are asking for lifetimes in a trait *definition*, we use `resolve_lifetimes_trait_definition` | |
328 | /// instead of `resolve_lifetimes`, which does not descend into the trait items and does not emit diagnostics. | |
329 | /// This allows us to avoid cycles. Importantly, if we ask for lifetimes for lifetimes that have an owner | |
330 | /// other than the trait itself (like the trait methods or associated types), then we just use the regular | |
331 | /// `resolve_lifetimes`. | |
2b03887a FG |
332 | fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: hir::OwnerId) -> &'tcx ResolveLifetimes { |
333 | let item_id = item_for(tcx, def_id.def_id); | |
334 | let local_def_id = item_id.owner_id.def_id; | |
335 | if item_id.owner_id == def_id { | |
336 | let item = tcx.hir().item(item_id); | |
cdc7bbd5 | 337 | match item.kind { |
2b03887a FG |
338 | hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(local_def_id), |
339 | _ => tcx.resolve_lifetimes(local_def_id), | |
cdc7bbd5 XL |
340 | } |
341 | } else { | |
2b03887a | 342 | tcx.resolve_lifetimes(local_def_id) |
cdc7bbd5 XL |
343 | } |
344 | } | |
345 | ||
346 | /// Finds the `Item` that contains the given `LocalDefId` | |
2b03887a | 347 | fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> hir::ItemId { |
5099ac24 | 348 | match tcx.hir().find_by_def_id(local_def_id) { |
cdc7bbd5 | 349 | Some(Node::Item(item)) => { |
2b03887a | 350 | return item.item_id(); |
cdc7bbd5 XL |
351 | } |
352 | _ => {} | |
353 | } | |
354 | let item = { | |
5099ac24 | 355 | let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id); |
c295e0f8 | 356 | let mut parent_iter = tcx.hir().parent_iter(hir_id); |
cdc7bbd5 XL |
357 | loop { |
358 | let node = parent_iter.next().map(|n| n.1); | |
359 | match node { | |
2b03887a | 360 | Some(hir::Node::Item(item)) => break item.item_id(), |
cdc7bbd5 XL |
361 | Some(hir::Node::Crate(_)) | None => bug!("Called `item_for` on an Item."), |
362 | _ => {} | |
363 | } | |
364 | } | |
365 | }; | |
366 | item | |
367 | } | |
368 | ||
cdc7bbd5 XL |
369 | fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind { |
370 | match region { | |
5e7ed085 | 371 | Region::LateBound(_, _, def_id) => { |
cdc7bbd5 XL |
372 | let name = tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local())); |
373 | ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name)) | |
374 | } | |
cdc7bbd5 XL |
375 | _ => bug!("{:?} is not a late region", region), |
376 | } | |
377 | } | |
378 | ||
379 | impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { | |
380 | /// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref. | |
381 | fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderScopeType) { | |
382 | let mut scope = self.scope; | |
383 | let mut supertrait_lifetimes = vec![]; | |
384 | loop { | |
385 | match scope { | |
386 | Scope::Body { .. } | Scope::Root => { | |
387 | break (vec![], BinderScopeType::Normal); | |
388 | } | |
389 | ||
390 | Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { | |
391 | scope = s; | |
392 | } | |
393 | ||
394 | Scope::Supertrait { s, lifetimes } => { | |
395 | supertrait_lifetimes = lifetimes.clone(); | |
396 | scope = s; | |
397 | } | |
398 | ||
399 | Scope::TraitRefBoundary { .. } => { | |
400 | // We should only see super trait lifetimes if there is a `Binder` above | |
401 | assert!(supertrait_lifetimes.is_empty()); | |
402 | break (vec![], BinderScopeType::Normal); | |
403 | } | |
404 | ||
405 | Scope::Binder { hir_id, .. } => { | |
406 | // Nested poly trait refs have the binders concatenated | |
407 | let mut full_binders = | |
408 | self.map.late_bound_vars.entry(*hir_id).or_default().clone(); | |
409 | full_binders.extend(supertrait_lifetimes.into_iter()); | |
410 | break (full_binders, BinderScopeType::Concatenating); | |
411 | } | |
412 | } | |
413 | } | |
414 | } | |
415 | } | |
dfeec247 | 416 | impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { |
5099ac24 | 417 | type NestedFilter = nested_filter::All; |
dfeec247 | 418 | |
5099ac24 FG |
419 | fn nested_visit_map(&mut self) -> Self::Map { |
420 | self.tcx.hir() | |
dfeec247 XL |
421 | } |
422 | ||
423 | // We want to nest trait/impl items in their parent, but nothing else. | |
424 | fn visit_nested_item(&mut self, _: hir::ItemId) {} | |
425 | ||
cdc7bbd5 XL |
426 | fn visit_trait_item_ref(&mut self, ii: &'tcx hir::TraitItemRef) { |
427 | if !self.trait_definition_only { | |
428 | intravisit::walk_trait_item_ref(self, ii) | |
429 | } | |
430 | } | |
431 | ||
dfeec247 | 432 | fn visit_nested_body(&mut self, body: hir::BodyId) { |
dfeec247 | 433 | let body = self.tcx.hir().body(body); |
923072b8 | 434 | self.with(Scope::Body { id: body.id(), s: self.scope }, |this| { |
dfeec247 XL |
435 | this.visit_body(body); |
436 | }); | |
dfeec247 XL |
437 | } |
438 | ||
923072b8 | 439 | fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { |
064997fb FG |
440 | if let hir::ExprKind::Closure(hir::Closure { |
441 | binder, bound_generic_params, fn_decl, .. | |
442 | }) = e.kind | |
443 | { | |
444 | if let &hir::ClosureBinder::For { span: for_sp, .. } = binder { | |
445 | fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> { | |
446 | struct V(Option<Span>); | |
447 | ||
448 | impl<'v> Visitor<'v> for V { | |
449 | fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { | |
450 | match t.kind { | |
451 | _ if self.0.is_some() => (), | |
452 | hir::TyKind::Infer => { | |
453 | self.0 = Some(t.span); | |
454 | } | |
455 | _ => intravisit::walk_ty(self, t), | |
456 | } | |
457 | } | |
458 | } | |
459 | ||
460 | let mut v = V(None); | |
461 | v.visit_ty(ty); | |
462 | v.0 | |
463 | } | |
464 | ||
465 | let infer_in_rt_sp = match fn_decl.output { | |
466 | hir::FnRetTy::DefaultReturn(sp) => Some(sp), | |
467 | hir::FnRetTy::Return(ty) => span_of_infer(ty), | |
468 | }; | |
469 | ||
470 | let infer_spans = fn_decl | |
471 | .inputs | |
472 | .into_iter() | |
473 | .filter_map(span_of_infer) | |
474 | .chain(infer_in_rt_sp) | |
475 | .collect::<Vec<_>>(); | |
476 | ||
477 | if !infer_spans.is_empty() { | |
478 | self.tcx.sess | |
479 | .struct_span_err( | |
480 | infer_spans, | |
481 | "implicit types in closure signatures are forbidden when `for<...>` is present", | |
482 | ) | |
483 | .span_label(for_sp, "`for<...>` is here") | |
484 | .emit(); | |
485 | } | |
486 | } | |
487 | ||
923072b8 FG |
488 | let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = |
489 | bound_generic_params | |
490 | .iter() | |
491 | .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) | |
492 | .enumerate() | |
493 | .map(|(late_bound_idx, param)| { | |
494 | let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param); | |
495 | let r = late_region_as_bound_region(self.tcx, &pair.1); | |
496 | (pair, r) | |
497 | }) | |
498 | .unzip(); | |
064997fb | 499 | |
2b03887a | 500 | self.record_late_bound_vars(e.hir_id, binders); |
923072b8 FG |
501 | let scope = Scope::Binder { |
502 | hir_id: e.hir_id, | |
503 | lifetimes, | |
504 | s: self.scope, | |
923072b8 | 505 | scope_type: BinderScopeType::Normal, |
923072b8 FG |
506 | where_bound_origin: None, |
507 | }; | |
064997fb | 508 | |
923072b8 FG |
509 | self.with(scope, |this| { |
510 | // a closure has no bounds, so everything | |
511 | // contained within is scoped within its binder. | |
512 | intravisit::walk_expr(this, e) | |
513 | }); | |
514 | } else { | |
515 | intravisit::walk_expr(self, e) | |
cdc7bbd5 XL |
516 | } |
517 | } | |
518 | ||
f2b60f7d | 519 | #[instrument(level = "debug", skip(self))] |
dfeec247 | 520 | fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { |
cdc7bbd5 XL |
521 | match &item.kind { |
522 | hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => { | |
523 | if let Some(of_trait) = of_trait { | |
2b03887a | 524 | self.record_late_bound_vars(of_trait.hir_ref_id, Vec::default()); |
cdc7bbd5 XL |
525 | } |
526 | } | |
527 | _ => {} | |
528 | } | |
dfeec247 | 529 | match item.kind { |
923072b8 | 530 | hir::ItemKind::Fn(_, ref generics, _) => { |
f2b60f7d | 531 | self.visit_early_late(item.hir_id(), generics, |this| { |
dfeec247 XL |
532 | intravisit::walk_item(this, item); |
533 | }); | |
dfeec247 XL |
534 | } |
535 | ||
536 | hir::ItemKind::ExternCrate(_) | |
537 | | hir::ItemKind::Use(..) | |
94222f64 | 538 | | hir::ItemKind::Macro(..) |
dfeec247 | 539 | | hir::ItemKind::Mod(..) |
fc512014 | 540 | | hir::ItemKind::ForeignMod { .. } |
dfeec247 XL |
541 | | hir::ItemKind::GlobalAsm(..) => { |
542 | // These sorts of items have no lifetime parameters at all. | |
543 | intravisit::walk_item(self, item); | |
544 | } | |
545 | hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { | |
546 | // No lifetime parameters, but implied 'static. | |
064997fb FG |
547 | self.with(Scope::Elision { s: self.scope }, |this| { |
548 | intravisit::walk_item(this, item) | |
549 | }); | |
dfeec247 | 550 | } |
f035d41b XL |
551 | hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => { |
552 | // Opaque types are visited when we visit the | |
553 | // `TyKind::OpaqueDef`, so that they have the lifetimes from | |
554 | // their parent opaque_ty in scope. | |
cdc7bbd5 XL |
555 | // |
556 | // The core idea here is that since OpaqueTys are generated with the impl Trait as | |
557 | // their owner, we can keep going until we find the Item that owns that. We then | |
558 | // conservatively add all resolved lifetimes. Otherwise we run into problems in | |
559 | // cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`. | |
2b03887a | 560 | for (_hir_id, node) in self.tcx.hir().parent_iter(item.owner_id.into()) { |
cdc7bbd5 XL |
561 | match node { |
562 | hir::Node::Item(parent_item) => { | |
2b03887a FG |
563 | let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes( |
564 | item_for(self.tcx, parent_item.owner_id.def_id).owner_id.def_id, | |
565 | ); | |
cdc7bbd5 XL |
566 | // We need to add *all* deps, since opaque tys may want them from *us* |
567 | for (&owner, defs) in resolved_lifetimes.defs.iter() { | |
568 | defs.iter().for_each(|(&local_id, region)| { | |
17df50a5 | 569 | self.map.defs.insert(hir::HirId { owner, local_id }, *region); |
cdc7bbd5 XL |
570 | }); |
571 | } | |
cdc7bbd5 XL |
572 | for (&owner, late_bound_vars) in |
573 | resolved_lifetimes.late_bound_vars.iter() | |
574 | { | |
575 | late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| { | |
2b03887a | 576 | self.record_late_bound_vars( |
cdc7bbd5 XL |
577 | hir::HirId { owner, local_id }, |
578 | late_bound_vars.clone(), | |
579 | ); | |
580 | }); | |
581 | } | |
582 | break; | |
583 | } | |
584 | hir::Node::Crate(_) => bug!("No Item about an OpaqueTy"), | |
585 | _ => {} | |
586 | } | |
587 | } | |
dfeec247 XL |
588 | } |
589 | hir::ItemKind::TyAlias(_, ref generics) | |
dfeec247 XL |
590 | | hir::ItemKind::Enum(_, ref generics) |
591 | | hir::ItemKind::Struct(_, ref generics) | |
592 | | hir::ItemKind::Union(_, ref generics) | |
593 | | hir::ItemKind::Trait(_, _, ref generics, ..) | |
594 | | hir::ItemKind::TraitAlias(ref generics, ..) | |
5869c6ff | 595 | | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => { |
dfeec247 | 596 | // These kinds of items have only early-bound lifetime parameters. |
dfeec247 XL |
597 | let lifetimes = generics |
598 | .params | |
599 | .iter() | |
600 | .filter_map(|param| match param.kind { | |
601 | GenericParamKind::Lifetime { .. } => { | |
f2b60f7d | 602 | Some(Region::early(self.tcx.hir(), param)) |
dfeec247 | 603 | } |
f2b60f7d | 604 | GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None, |
dfeec247 XL |
605 | }) |
606 | .collect(); | |
2b03887a | 607 | self.record_late_bound_vars(item.hir_id(), vec![]); |
dfeec247 | 608 | let scope = Scope::Binder { |
cdc7bbd5 | 609 | hir_id: item.hir_id(), |
dfeec247 | 610 | lifetimes, |
cdc7bbd5 | 611 | scope_type: BinderScopeType::Normal, |
dfeec247 | 612 | s: ROOT_SCOPE, |
04454e1e | 613 | where_bound_origin: None, |
dfeec247 | 614 | }; |
923072b8 | 615 | self.with(scope, |this| { |
cdc7bbd5 | 616 | let scope = Scope::TraitRefBoundary { s: this.scope }; |
923072b8 | 617 | this.with(scope, |this| { |
cdc7bbd5 XL |
618 | intravisit::walk_item(this, item); |
619 | }); | |
dfeec247 | 620 | }); |
dfeec247 XL |
621 | } |
622 | } | |
623 | } | |
624 | ||
625 | fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { | |
626 | match item.kind { | |
923072b8 | 627 | hir::ForeignItemKind::Fn(_, _, ref generics) => { |
f2b60f7d | 628 | self.visit_early_late(item.hir_id(), generics, |this| { |
dfeec247 XL |
629 | intravisit::walk_foreign_item(this, item); |
630 | }) | |
631 | } | |
632 | hir::ForeignItemKind::Static(..) => { | |
633 | intravisit::walk_foreign_item(self, item); | |
634 | } | |
635 | hir::ForeignItemKind::Type => { | |
636 | intravisit::walk_foreign_item(self, item); | |
637 | } | |
638 | } | |
639 | } | |
640 | ||
f2b60f7d | 641 | #[instrument(level = "debug", skip(self))] |
dfeec247 | 642 | fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { |
dfeec247 XL |
643 | match ty.kind { |
644 | hir::TyKind::BareFn(ref c) => { | |
923072b8 | 645 | let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c |
cdc7bbd5 XL |
646 | .generic_params |
647 | .iter() | |
3c0e092e | 648 | .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) |
cdc7bbd5 XL |
649 | .enumerate() |
650 | .map(|(late_bound_idx, param)| { | |
5099ac24 | 651 | let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param); |
cdc7bbd5 XL |
652 | let r = late_region_as_bound_region(self.tcx, &pair.1); |
653 | (pair, r) | |
654 | }) | |
655 | .unzip(); | |
2b03887a | 656 | self.record_late_bound_vars(ty.hir_id, binders); |
dfeec247 | 657 | let scope = Scope::Binder { |
cdc7bbd5 XL |
658 | hir_id: ty.hir_id, |
659 | lifetimes, | |
dfeec247 | 660 | s: self.scope, |
cdc7bbd5 | 661 | scope_type: BinderScopeType::Normal, |
04454e1e | 662 | where_bound_origin: None, |
dfeec247 | 663 | }; |
923072b8 | 664 | self.with(scope, |this| { |
dfeec247 XL |
665 | // a bare fn has no bounds, so everything |
666 | // contained within is scoped within its binder. | |
dfeec247 XL |
667 | intravisit::walk_ty(this, ty); |
668 | }); | |
dfeec247 | 669 | } |
6a06907d | 670 | hir::TyKind::TraitObject(bounds, ref lifetime, _) => { |
cdc7bbd5 XL |
671 | debug!(?bounds, ?lifetime, "TraitObject"); |
672 | let scope = Scope::TraitRefBoundary { s: self.scope }; | |
923072b8 | 673 | self.with(scope, |this| { |
cdc7bbd5 | 674 | for bound in bounds { |
f2b60f7d | 675 | this.visit_poly_trait_ref(bound); |
cdc7bbd5 XL |
676 | } |
677 | }); | |
dfeec247 | 678 | match lifetime.name { |
dfeec247 XL |
679 | LifetimeName::ImplicitObjectLifetimeDefault => { |
680 | // If the user does not write *anything*, we | |
681 | // use the object lifetime defaulting | |
682 | // rules. So e.g., `Box<dyn Debug>` becomes | |
683 | // `Box<dyn Debug + 'static>`. | |
684 | self.resolve_object_lifetime_default(lifetime) | |
685 | } | |
064997fb | 686 | LifetimeName::Infer => { |
dfeec247 XL |
687 | // If the user writes `'_`, we use the *ordinary* elision |
688 | // rules. So the `'_` in e.g., `Box<dyn Debug + '_>` will be | |
689 | // resolved the same as the `'_` in `&'_ Foo`. | |
690 | // | |
691 | // cc #48468 | |
dfeec247 | 692 | } |
923072b8 | 693 | LifetimeName::Param(..) | LifetimeName::Static => { |
dfeec247 XL |
694 | // If the user wrote an explicit name, use that. |
695 | self.visit_lifetime(lifetime); | |
696 | } | |
697 | LifetimeName::Error => {} | |
698 | } | |
699 | } | |
700 | hir::TyKind::Rptr(ref lifetime_ref, ref mt) => { | |
701 | self.visit_lifetime(lifetime_ref); | |
702 | let scope = Scope::ObjectLifetimeDefault { | |
703 | lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(), | |
704 | s: self.scope, | |
705 | }; | |
923072b8 | 706 | self.with(scope, |this| this.visit_ty(&mt.ty)); |
dfeec247 | 707 | } |
f2b60f7d | 708 | hir::TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => { |
dfeec247 XL |
709 | // Resolve the lifetimes in the bounds to the lifetime defs in the generics. |
710 | // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to | |
711 | // `type MyAnonTy<'b> = impl MyTrait<'b>;` | |
712 | // ^ ^ this gets resolved in the scope of | |
713 | // the opaque_ty generics | |
6a06907d | 714 | let opaque_ty = self.tcx.hir().item(item_id); |
f035d41b | 715 | let (generics, bounds) = match opaque_ty.kind { |
a2a8927a XL |
716 | hir::ItemKind::OpaqueTy(hir::OpaqueTy { |
717 | origin: hir::OpaqueTyOrigin::TyAlias, | |
718 | .. | |
719 | }) => { | |
dfeec247 | 720 | intravisit::walk_ty(self, ty); |
f035d41b XL |
721 | |
722 | // Elided lifetimes are not allowed in non-return | |
723 | // position impl Trait | |
cdc7bbd5 | 724 | let scope = Scope::TraitRefBoundary { s: self.scope }; |
923072b8 | 725 | self.with(scope, |this| { |
064997fb | 726 | let scope = Scope::Elision { s: this.scope }; |
923072b8 | 727 | this.with(scope, |this| { |
cdc7bbd5 XL |
728 | intravisit::walk_item(this, opaque_ty); |
729 | }) | |
f035d41b XL |
730 | }); |
731 | ||
dfeec247 XL |
732 | return; |
733 | } | |
f035d41b | 734 | hir::ItemKind::OpaqueTy(hir::OpaqueTy { |
a2a8927a | 735 | origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..), |
f035d41b XL |
736 | ref generics, |
737 | bounds, | |
738 | .. | |
739 | }) => (generics, bounds), | |
dfeec247 XL |
740 | ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), |
741 | }; | |
742 | ||
743 | // Resolve the lifetimes that are applied to the opaque type. | |
744 | // These are resolved in the current scope. | |
745 | // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to | |
746 | // `fn foo<'a>() -> MyAnonTy<'a> { ... }` | |
747 | // ^ ^this gets resolved in the current scope | |
748 | for lifetime in lifetimes { | |
5099ac24 FG |
749 | let hir::GenericArg::Lifetime(lifetime) = lifetime else { |
750 | continue | |
751 | }; | |
752 | self.visit_lifetime(lifetime); | |
753 | ||
754 | // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>` | |
755 | // and ban them. Type variables instantiated inside binders aren't | |
756 | // well-supported at the moment, so this doesn't work. | |
757 | // In the future, this should be fixed and this error should be removed. | |
758 | let def = self.map.defs.get(&lifetime.hir_id).cloned(); | |
5e7ed085 | 759 | let Some(Region::LateBound(_, _, def_id)) = def else { |
5099ac24 FG |
760 | continue |
761 | }; | |
762 | let Some(def_id) = def_id.as_local() else { | |
763 | continue | |
764 | }; | |
765 | let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); | |
766 | // Ensure that the parent of the def is an item, not HRTB | |
767 | let parent_id = self.tcx.hir().get_parent_node(hir_id); | |
768 | if !parent_id.is_owner() { | |
769 | if !self.trait_definition_only { | |
770 | struct_span_err!( | |
771 | self.tcx.sess, | |
772 | lifetime.span, | |
773 | E0657, | |
774 | "`impl Trait` can only capture lifetimes \ | |
775 | bound at the fn or impl level" | |
776 | ) | |
777 | .emit(); | |
dfeec247 | 778 | } |
5099ac24 | 779 | self.uninsert_lifetime_on_error(lifetime, def.unwrap()); |
dfeec247 | 780 | } |
5e7ed085 FG |
781 | if let hir::Node::Item(hir::Item { |
782 | kind: hir::ItemKind::OpaqueTy { .. }, .. | |
783 | }) = self.tcx.hir().get(parent_id) | |
784 | { | |
785 | if !self.trait_definition_only { | |
786 | let mut err = self.tcx.sess.struct_span_err( | |
787 | lifetime.span, | |
788 | "higher kinded lifetime bounds on nested opaque types are not supported yet", | |
789 | ); | |
790 | err.span_note(self.tcx.def_span(def_id), "lifetime declared here"); | |
791 | err.emit(); | |
792 | } | |
793 | self.uninsert_lifetime_on_error(lifetime, def.unwrap()); | |
794 | } | |
dfeec247 XL |
795 | } |
796 | ||
797 | // We want to start our early-bound indices at the end of the parent scope, | |
798 | // not including any parent `impl Trait`s. | |
17df50a5 | 799 | let mut lifetimes = FxIndexMap::default(); |
064997fb | 800 | debug!(?generics.params); |
dfeec247 XL |
801 | for param in generics.params { |
802 | match param.kind { | |
803 | GenericParamKind::Lifetime { .. } => { | |
f2b60f7d | 804 | let (def_id, reg) = Region::early(self.tcx.hir(), ¶m); |
064997fb | 805 | lifetimes.insert(def_id, reg); |
dfeec247 | 806 | } |
f2b60f7d | 807 | GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {} |
dfeec247 XL |
808 | } |
809 | } | |
2b03887a | 810 | self.record_late_bound_vars(ty.hir_id, vec![]); |
dfeec247 | 811 | |
064997fb FG |
812 | let scope = Scope::Binder { |
813 | hir_id: ty.hir_id, | |
814 | lifetimes, | |
064997fb | 815 | s: self.scope, |
064997fb FG |
816 | scope_type: BinderScopeType::Normal, |
817 | where_bound_origin: None, | |
818 | }; | |
819 | self.with(scope, |this| { | |
820 | let scope = Scope::TraitRefBoundary { s: this.scope }; | |
821 | this.with(scope, |this| { | |
822 | this.visit_generics(generics); | |
823 | for bound in bounds { | |
824 | this.visit_param_bound(bound); | |
825 | } | |
826 | }) | |
827 | }); | |
dfeec247 XL |
828 | } |
829 | _ => intravisit::walk_ty(self, ty), | |
830 | } | |
831 | } | |
832 | ||
f2b60f7d | 833 | #[instrument(level = "debug", skip(self))] |
dfeec247 XL |
834 | fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { |
835 | use self::hir::TraitItemKind::*; | |
dfeec247 | 836 | match trait_item.kind { |
923072b8 | 837 | Fn(_, _) => { |
f2b60f7d FG |
838 | self.visit_early_late(trait_item.hir_id(), &trait_item.generics, |this| { |
839 | intravisit::walk_trait_item(this, trait_item) | |
840 | }); | |
dfeec247 XL |
841 | } |
842 | Type(bounds, ref ty) => { | |
843 | let generics = &trait_item.generics; | |
dfeec247 XL |
844 | let lifetimes = generics |
845 | .params | |
846 | .iter() | |
847 | .filter_map(|param| match param.kind { | |
848 | GenericParamKind::Lifetime { .. } => { | |
f2b60f7d | 849 | Some(Region::early(self.tcx.hir(), param)) |
dfeec247 | 850 | } |
f2b60f7d | 851 | GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None, |
dfeec247 XL |
852 | }) |
853 | .collect(); | |
2b03887a | 854 | self.record_late_bound_vars(trait_item.hir_id(), vec![]); |
dfeec247 | 855 | let scope = Scope::Binder { |
cdc7bbd5 | 856 | hir_id: trait_item.hir_id(), |
dfeec247 | 857 | lifetimes, |
dfeec247 | 858 | s: self.scope, |
cdc7bbd5 | 859 | scope_type: BinderScopeType::Normal, |
04454e1e | 860 | where_bound_origin: None, |
dfeec247 | 861 | }; |
923072b8 | 862 | self.with(scope, |this| { |
cdc7bbd5 | 863 | let scope = Scope::TraitRefBoundary { s: this.scope }; |
923072b8 | 864 | this.with(scope, |this| { |
cdc7bbd5 XL |
865 | this.visit_generics(generics); |
866 | for bound in bounds { | |
867 | this.visit_param_bound(bound); | |
868 | } | |
869 | if let Some(ty) = ty { | |
870 | this.visit_ty(ty); | |
871 | } | |
872 | }) | |
dfeec247 XL |
873 | }); |
874 | } | |
875 | Const(_, _) => { | |
876 | // Only methods and types support generics. | |
877 | assert!(trait_item.generics.params.is_empty()); | |
878 | intravisit::walk_trait_item(self, trait_item); | |
879 | } | |
880 | } | |
dfeec247 XL |
881 | } |
882 | ||
f2b60f7d | 883 | #[instrument(level = "debug", skip(self))] |
dfeec247 XL |
884 | fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { |
885 | use self::hir::ImplItemKind::*; | |
dfeec247 | 886 | match impl_item.kind { |
f2b60f7d FG |
887 | Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| { |
888 | intravisit::walk_impl_item(this, impl_item) | |
889 | }), | |
2b03887a | 890 | Type(ref ty) => { |
dfeec247 | 891 | let generics = &impl_item.generics; |
923072b8 | 892 | let lifetimes: FxIndexMap<LocalDefId, Region> = generics |
dfeec247 XL |
893 | .params |
894 | .iter() | |
895 | .filter_map(|param| match param.kind { | |
896 | GenericParamKind::Lifetime { .. } => { | |
f2b60f7d | 897 | Some(Region::early(self.tcx.hir(), param)) |
dfeec247 | 898 | } |
f2b60f7d | 899 | GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None, |
dfeec247 XL |
900 | }) |
901 | .collect(); | |
2b03887a | 902 | self.record_late_bound_vars(impl_item.hir_id(), vec![]); |
dfeec247 | 903 | let scope = Scope::Binder { |
2b03887a | 904 | hir_id: impl_item.hir_id(), |
dfeec247 | 905 | lifetimes, |
dfeec247 | 906 | s: self.scope, |
cdc7bbd5 | 907 | scope_type: BinderScopeType::Normal, |
04454e1e | 908 | where_bound_origin: None, |
dfeec247 | 909 | }; |
923072b8 | 910 | self.with(scope, |this| { |
cdc7bbd5 | 911 | let scope = Scope::TraitRefBoundary { s: this.scope }; |
923072b8 | 912 | this.with(scope, |this| { |
cdc7bbd5 XL |
913 | this.visit_generics(generics); |
914 | this.visit_ty(ty); | |
915 | }) | |
dfeec247 XL |
916 | }); |
917 | } | |
dfeec247 XL |
918 | Const(_, _) => { |
919 | // Only methods and types support generics. | |
920 | assert!(impl_item.generics.params.is_empty()); | |
921 | intravisit::walk_impl_item(self, impl_item); | |
922 | } | |
923 | } | |
dfeec247 XL |
924 | } |
925 | ||
f2b60f7d | 926 | #[instrument(level = "debug", skip(self))] |
dfeec247 | 927 | fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { |
923072b8 | 928 | match lifetime_ref.name { |
923072b8 FG |
929 | hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static), |
930 | hir::LifetimeName::Param(param_def_id, _) => { | |
931 | self.resolve_lifetime_ref(param_def_id, lifetime_ref) | |
932 | } | |
933 | // If we've already reported an error, just ignore `lifetime_ref`. | |
934 | hir::LifetimeName::Error => {} | |
064997fb FG |
935 | // Those will be resolved by typechecking. |
936 | hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Infer => {} | |
17df50a5 | 937 | } |
17df50a5 XL |
938 | } |
939 | ||
dfeec247 XL |
940 | fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) { |
941 | for (i, segment) in path.segments.iter().enumerate() { | |
942 | let depth = path.segments.len() - i - 1; | |
943 | if let Some(ref args) = segment.args { | |
944 | self.visit_segment_args(path.res, depth, args); | |
945 | } | |
17df50a5 XL |
946 | } |
947 | } | |
948 | ||
064997fb FG |
949 | fn visit_fn( |
950 | &mut self, | |
951 | fk: intravisit::FnKind<'tcx>, | |
952 | fd: &'tcx hir::FnDecl<'tcx>, | |
953 | body_id: hir::BodyId, | |
954 | _: Span, | |
955 | _: hir::HirId, | |
956 | ) { | |
dfeec247 | 957 | let output = match fd.output { |
74b04a01 XL |
958 | hir::FnRetTy::DefaultReturn(_) => None, |
959 | hir::FnRetTy::Return(ref ty) => Some(&**ty), | |
dfeec247 | 960 | }; |
064997fb FG |
961 | self.visit_fn_like_elision(&fd.inputs, output, matches!(fk, intravisit::FnKind::Closure)); |
962 | intravisit::walk_fn_kind(self, fk); | |
963 | self.visit_nested_body(body_id) | |
dfeec247 XL |
964 | } |
965 | ||
966 | fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { | |
cdc7bbd5 | 967 | let scope = Scope::TraitRefBoundary { s: self.scope }; |
923072b8 | 968 | self.with(scope, |this| { |
cdc7bbd5 XL |
969 | for param in generics.params { |
970 | match param.kind { | |
971 | GenericParamKind::Lifetime { .. } => {} | |
972 | GenericParamKind::Type { ref default, .. } => { | |
cdc7bbd5 XL |
973 | if let Some(ref ty) = default { |
974 | this.visit_ty(&ty); | |
975 | } | |
976 | } | |
a2a8927a | 977 | GenericParamKind::Const { ref ty, default } => { |
cdc7bbd5 | 978 | this.visit_ty(&ty); |
a2a8927a XL |
979 | if let Some(default) = default { |
980 | this.visit_body(this.tcx.hir().body(default.body)); | |
981 | } | |
dfeec247 XL |
982 | } |
983 | } | |
cdc7bbd5 | 984 | } |
04454e1e | 985 | for predicate in generics.predicates { |
cdc7bbd5 XL |
986 | match predicate { |
987 | &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { | |
2b03887a | 988 | hir_id, |
cdc7bbd5 XL |
989 | ref bounded_ty, |
990 | bounds, | |
991 | ref bound_generic_params, | |
04454e1e | 992 | origin, |
cdc7bbd5 XL |
993 | .. |
994 | }) => { | |
2b03887a | 995 | let lifetimes: FxIndexMap<LocalDefId, Region> = |
cdc7bbd5 XL |
996 | bound_generic_params |
997 | .iter() | |
3c0e092e XL |
998 | .filter(|param| { |
999 | matches!(param.kind, GenericParamKind::Lifetime { .. }) | |
cdc7bbd5 XL |
1000 | }) |
1001 | .enumerate() | |
1002 | .map(|(late_bound_idx, param)| { | |
2b03887a FG |
1003 | Region::late(late_bound_idx as u32, this.tcx.hir(), param) |
1004 | }) | |
1005 | .collect(); | |
1006 | let binders: Vec<_> = | |
1007 | lifetimes | |
1008 | .iter() | |
1009 | .map(|(_, region)| { | |
1010 | late_region_as_bound_region(this.tcx, region) | |
cdc7bbd5 | 1011 | }) |
2b03887a FG |
1012 | .collect(); |
1013 | this.record_late_bound_vars(hir_id, binders.clone()); | |
cdc7bbd5 XL |
1014 | // Even if there are no lifetimes defined here, we still wrap it in a binder |
1015 | // scope. If there happens to be a nested poly trait ref (an error), that | |
1016 | // will be `Concatenating` anyways, so we don't have to worry about the depth | |
1017 | // being wrong. | |
dfeec247 | 1018 | let scope = Scope::Binder { |
2b03887a | 1019 | hir_id, |
dfeec247 | 1020 | lifetimes, |
cdc7bbd5 | 1021 | s: this.scope, |
cdc7bbd5 | 1022 | scope_type: BinderScopeType::Normal, |
04454e1e | 1023 | where_bound_origin: Some(origin), |
dfeec247 | 1024 | }; |
923072b8 | 1025 | this.with(scope, |this| { |
dfeec247 XL |
1026 | this.visit_ty(&bounded_ty); |
1027 | walk_list!(this, visit_param_bound, bounds); | |
cdc7bbd5 XL |
1028 | }) |
1029 | } | |
1030 | &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { | |
1031 | ref lifetime, | |
1032 | bounds, | |
1033 | .. | |
1034 | }) => { | |
1035 | this.visit_lifetime(lifetime); | |
1036 | walk_list!(this, visit_param_bound, bounds); | |
04454e1e FG |
1037 | |
1038 | if lifetime.name != hir::LifetimeName::Static { | |
1039 | for bound in bounds { | |
1040 | let hir::GenericBound::Outlives(ref lt) = bound else { | |
1041 | continue; | |
1042 | }; | |
1043 | if lt.name != hir::LifetimeName::Static { | |
1044 | continue; | |
1045 | } | |
1046 | this.insert_lifetime(lt, Region::Static); | |
1047 | this.tcx | |
1048 | .sess | |
1049 | .struct_span_warn( | |
1050 | lifetime.span, | |
1051 | &format!( | |
1052 | "unnecessary lifetime parameter `{}`", | |
1053 | lifetime.name.ident(), | |
1054 | ), | |
1055 | ) | |
1056 | .help(&format!( | |
1057 | "you can use the `'static` lifetime directly, in place of `{}`", | |
1058 | lifetime.name.ident(), | |
1059 | )) | |
1060 | .emit(); | |
1061 | } | |
1062 | } | |
cdc7bbd5 XL |
1063 | } |
1064 | &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { | |
1065 | ref lhs_ty, | |
1066 | ref rhs_ty, | |
1067 | .. | |
1068 | }) => { | |
1069 | this.visit_ty(lhs_ty); | |
1070 | this.visit_ty(rhs_ty); | |
dfeec247 | 1071 | } |
dfeec247 XL |
1072 | } |
1073 | } | |
cdc7bbd5 | 1074 | }) |
dfeec247 XL |
1075 | } |
1076 | ||
3dfed10e XL |
1077 | fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) { |
1078 | match bound { | |
cdc7bbd5 XL |
1079 | hir::GenericBound::LangItemTrait(_, _, hir_id, _) => { |
1080 | // FIXME(jackh726): This is pretty weird. `LangItemTrait` doesn't go | |
1081 | // through the regular poly trait ref code, so we don't get another | |
1082 | // chance to introduce a binder. For now, I'm keeping the existing logic | |
1083 | // of "if there isn't a Binder scope above us, add one", but I | |
1084 | // imagine there's a better way to go about this. | |
1085 | let (binders, scope_type) = self.poly_trait_ref_binder_info(); | |
1086 | ||
2b03887a | 1087 | self.record_late_bound_vars(*hir_id, binders); |
3dfed10e | 1088 | let scope = Scope::Binder { |
cdc7bbd5 | 1089 | hir_id: *hir_id, |
17df50a5 | 1090 | lifetimes: FxIndexMap::default(), |
3dfed10e | 1091 | s: self.scope, |
cdc7bbd5 | 1092 | scope_type, |
04454e1e | 1093 | where_bound_origin: None, |
3dfed10e | 1094 | }; |
923072b8 | 1095 | self.with(scope, |this| { |
3dfed10e XL |
1096 | intravisit::walk_param_bound(this, bound); |
1097 | }); | |
1098 | } | |
1099 | _ => intravisit::walk_param_bound(self, bound), | |
1100 | } | |
1101 | } | |
1102 | ||
f2b60f7d | 1103 | fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) { |
dfeec247 XL |
1104 | debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); |
1105 | ||
cdc7bbd5 XL |
1106 | let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); |
1107 | ||
1108 | let initial_bound_vars = binders.len() as u32; | |
923072b8 | 1109 | let mut lifetimes: FxIndexMap<LocalDefId, Region> = FxIndexMap::default(); |
cdc7bbd5 XL |
1110 | let binders_iter = trait_ref |
1111 | .bound_generic_params | |
1112 | .iter() | |
3c0e092e | 1113 | .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) |
cdc7bbd5 XL |
1114 | .enumerate() |
1115 | .map(|(late_bound_idx, param)| { | |
5099ac24 FG |
1116 | let pair = |
1117 | Region::late(initial_bound_vars + late_bound_idx as u32, self.tcx.hir(), param); | |
cdc7bbd5 XL |
1118 | let r = late_region_as_bound_region(self.tcx, &pair.1); |
1119 | lifetimes.insert(pair.0, pair.1); | |
1120 | r | |
f035d41b | 1121 | }); |
cdc7bbd5 XL |
1122 | binders.extend(binders_iter); |
1123 | ||
1124 | debug!(?binders); | |
2b03887a | 1125 | self.record_late_bound_vars(trait_ref.trait_ref.hir_ref_id, binders); |
cdc7bbd5 XL |
1126 | |
1127 | // Always introduce a scope here, even if this is in a where clause and | |
1128 | // we introduced the binders around the bounded Ty. In that case, we | |
1129 | // just reuse the concatenation functionality also present in nested trait | |
1130 | // refs. | |
1131 | let scope = Scope::Binder { | |
1132 | hir_id: trait_ref.trait_ref.hir_ref_id, | |
1133 | lifetimes, | |
1134 | s: self.scope, | |
cdc7bbd5 | 1135 | scope_type, |
04454e1e | 1136 | where_bound_origin: None, |
cdc7bbd5 | 1137 | }; |
923072b8 | 1138 | self.with(scope, |this| { |
cdc7bbd5 XL |
1139 | walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); |
1140 | this.visit_trait_ref(&trait_ref.trait_ref); | |
1141 | }); | |
dfeec247 XL |
1142 | } |
1143 | } | |
1144 | ||
f2b60f7d FG |
1145 | fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> ObjectLifetimeDefault { |
1146 | debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam); | |
1147 | let param_def_id = param_def_id.expect_local(); | |
1148 | let parent_def_id = tcx.local_parent(param_def_id); | |
1149 | let generics = tcx.hir().get_generics(parent_def_id).unwrap(); | |
1150 | let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id); | |
1151 | let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap(); | |
1152 | ||
1153 | // Scan the bounds and where-clauses on parameters to extract bounds | |
1154 | // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` | |
1155 | // for each type parameter. | |
1156 | match param.kind { | |
5099ac24 FG |
1157 | GenericParamKind::Type { .. } => { |
1158 | let mut set = Set1::Empty; | |
dfeec247 | 1159 | |
f2b60f7d FG |
1160 | // Look for `type: ...` where clauses. |
1161 | for bound in generics.bounds_for_param(param_def_id) { | |
5099ac24 FG |
1162 | // Ignore `for<'a> type: ...` as they can change what |
1163 | // lifetimes mean (although we could "just" handle it). | |
f2b60f7d | 1164 | if !bound.bound_generic_params.is_empty() { |
5099ac24 | 1165 | continue; |
dfeec247 XL |
1166 | } |
1167 | ||
f2b60f7d FG |
1168 | for bound in bound.bounds { |
1169 | if let hir::GenericBound::Outlives(ref lifetime) = *bound { | |
1170 | set.insert(lifetime.name.normalize_to_macros_2_0()); | |
1171 | } | |
5099ac24 | 1172 | } |
dfeec247 | 1173 | } |
5099ac24 | 1174 | |
f2b60f7d FG |
1175 | match set { |
1176 | Set1::Empty => ObjectLifetimeDefault::Empty, | |
1177 | Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static, | |
1178 | Set1::One(hir::LifetimeName::Param(param_def_id, _)) => { | |
1179 | ObjectLifetimeDefault::Param(param_def_id.to_def_id()) | |
5099ac24 | 1180 | } |
f2b60f7d FG |
1181 | _ => ObjectLifetimeDefault::Ambiguous, |
1182 | } | |
5099ac24 | 1183 | } |
f2b60f7d FG |
1184 | _ => { |
1185 | bug!("object_lifetime_default_raw must only be called on a type parameter") | |
5099ac24 | 1186 | } |
f2b60f7d | 1187 | } |
dfeec247 XL |
1188 | } |
1189 | ||
1190 | impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { | |
dfeec247 XL |
1191 | fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F) |
1192 | where | |
923072b8 | 1193 | F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), |
dfeec247 | 1194 | { |
923072b8 | 1195 | let LifetimeContext { tcx, map, .. } = self; |
dfeec247 XL |
1196 | let mut this = LifetimeContext { |
1197 | tcx: *tcx, | |
74b04a01 | 1198 | map, |
dfeec247 | 1199 | scope: &wrap_scope, |
cdc7bbd5 | 1200 | trait_definition_only: self.trait_definition_only, |
dfeec247 | 1201 | }; |
f2b60f7d | 1202 | let span = debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); |
cdc7bbd5 XL |
1203 | { |
1204 | let _enter = span.enter(); | |
923072b8 | 1205 | f(&mut this); |
cdc7bbd5 | 1206 | } |
dfeec247 XL |
1207 | } |
1208 | ||
2b03887a FG |
1209 | fn record_late_bound_vars(&mut self, hir_id: hir::HirId, binder: Vec<ty::BoundVariableKind>) { |
1210 | if let Some(old) = self.map.late_bound_vars.insert(hir_id, binder) { | |
1211 | bug!( | |
1212 | "overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}", | |
1213 | self.map.late_bound_vars[&hir_id] | |
1214 | ) | |
1215 | } | |
1216 | } | |
1217 | ||
dfeec247 XL |
1218 | /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. |
1219 | /// | |
1220 | /// Handles visiting fns and methods. These are a bit complicated because we must distinguish | |
1221 | /// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear | |
1222 | /// within type bounds; those are early bound lifetimes, and the rest are late bound. | |
1223 | /// | |
1224 | /// For example: | |
1225 | /// | |
1226 | /// fn foo<'a,'b,'c,T:Trait<'b>>(...) | |
1227 | /// | |
1228 | /// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound | |
1229 | /// lifetimes may be interspersed together. | |
1230 | /// | |
1231 | /// If early bound lifetimes are present, we separate them into their own list (and likewise | |
1232 | /// for late bound). They will be numbered sequentially, starting from the lowest index that is | |
1233 | /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late | |
1234 | /// bound lifetimes are resolved by name and associated with a binder ID (`binder_id`), so the | |
1235 | /// ordering is not important there. | |
1236 | fn visit_early_late<F>( | |
1237 | &mut self, | |
cdc7bbd5 | 1238 | hir_id: hir::HirId, |
dfeec247 XL |
1239 | generics: &'tcx hir::Generics<'tcx>, |
1240 | walk: F, | |
1241 | ) where | |
1242 | F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), | |
1243 | { | |
cdc7bbd5 | 1244 | let mut named_late_bound_vars = 0; |
923072b8 | 1245 | let lifetimes: FxIndexMap<LocalDefId, Region> = generics |
dfeec247 XL |
1246 | .params |
1247 | .iter() | |
1248 | .filter_map(|param| match param.kind { | |
1249 | GenericParamKind::Lifetime { .. } => { | |
923072b8 | 1250 | if self.tcx.is_late_bound(param.hir_id) { |
cdc7bbd5 XL |
1251 | let late_bound_idx = named_late_bound_vars; |
1252 | named_late_bound_vars += 1; | |
5099ac24 | 1253 | Some(Region::late(late_bound_idx, self.tcx.hir(), param)) |
dfeec247 | 1254 | } else { |
f2b60f7d | 1255 | Some(Region::early(self.tcx.hir(), param)) |
dfeec247 XL |
1256 | } |
1257 | } | |
f2b60f7d | 1258 | GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None, |
dfeec247 XL |
1259 | }) |
1260 | .collect(); | |
dfeec247 | 1261 | |
cdc7bbd5 XL |
1262 | let binders: Vec<_> = generics |
1263 | .params | |
1264 | .iter() | |
3c0e092e XL |
1265 | .filter(|param| { |
1266 | matches!(param.kind, GenericParamKind::Lifetime { .. }) | |
923072b8 | 1267 | && self.tcx.is_late_bound(param.hir_id) |
cdc7bbd5 XL |
1268 | }) |
1269 | .enumerate() | |
1270 | .map(|(late_bound_idx, param)| { | |
5099ac24 | 1271 | let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param); |
3c0e092e | 1272 | late_region_as_bound_region(self.tcx, &pair.1) |
cdc7bbd5 XL |
1273 | }) |
1274 | .collect(); | |
2b03887a | 1275 | self.record_late_bound_vars(hir_id, binders); |
dfeec247 | 1276 | let scope = Scope::Binder { |
cdc7bbd5 | 1277 | hir_id, |
dfeec247 | 1278 | lifetimes, |
dfeec247 | 1279 | s: self.scope, |
cdc7bbd5 | 1280 | scope_type: BinderScopeType::Normal, |
04454e1e | 1281 | where_bound_origin: None, |
dfeec247 | 1282 | }; |
923072b8 | 1283 | self.with(scope, walk); |
dfeec247 XL |
1284 | } |
1285 | ||
f2b60f7d | 1286 | #[instrument(level = "debug", skip(self))] |
923072b8 FG |
1287 | fn resolve_lifetime_ref( |
1288 | &mut self, | |
1289 | region_def_id: LocalDefId, | |
1290 | lifetime_ref: &'tcx hir::Lifetime, | |
1291 | ) { | |
dfeec247 XL |
1292 | // Walk up the scope chain, tracking the number of fn scopes |
1293 | // that we pass through, until we find a lifetime with the | |
1294 | // given name or we run out of scopes. | |
1295 | // search. | |
1296 | let mut late_depth = 0; | |
1297 | let mut scope = self.scope; | |
1298 | let mut outermost_body = None; | |
1299 | let result = loop { | |
1300 | match *scope { | |
1301 | Scope::Body { id, s } => { | |
1302 | outermost_body = Some(id); | |
1303 | scope = s; | |
1304 | } | |
1305 | ||
1306 | Scope::Root => { | |
1307 | break None; | |
1308 | } | |
1309 | ||
064997fb | 1310 | Scope::Binder { ref lifetimes, scope_type, s, where_bound_origin, .. } => { |
923072b8 FG |
1311 | if let Some(&def) = lifetimes.get(®ion_def_id) { |
1312 | break Some(def.shifted(late_depth)); | |
dfeec247 | 1313 | } |
cdc7bbd5 XL |
1314 | match scope_type { |
1315 | BinderScopeType::Normal => late_depth += 1, | |
1316 | BinderScopeType::Concatenating => {} | |
1317 | } | |
064997fb FG |
1318 | // Fresh lifetimes in APIT used to be allowed in async fns and forbidden in |
1319 | // regular fns. | |
1320 | if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin | |
1321 | && let hir::LifetimeName::Param(_, hir::ParamName::Fresh) = lifetime_ref.name | |
2b03887a | 1322 | && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id) |
064997fb FG |
1323 | && !self.tcx.features().anonymous_lifetime_in_impl_trait |
1324 | { | |
2b03887a | 1325 | let mut diag = rustc_session::parse::feature_err( |
064997fb FG |
1326 | &self.tcx.sess.parse_sess, |
1327 | sym::anonymous_lifetime_in_impl_trait, | |
1328 | lifetime_ref.span, | |
1329 | "anonymous lifetimes in `impl Trait` are unstable", | |
2b03887a FG |
1330 | ); |
1331 | ||
1332 | match self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id) { | |
1333 | Some(generics) => { | |
1334 | ||
1335 | let new_param_sugg_tuple; | |
1336 | ||
1337 | new_param_sugg_tuple = match generics.span_for_param_suggestion() { | |
1338 | Some(_) => { | |
1339 | Some((self.tcx.sess.source_map().span_through_char(generics.span, '<').shrink_to_hi(), "'a, ".to_owned())) | |
1340 | }, | |
1341 | None => Some((generics.span, "<'a>".to_owned())) | |
1342 | }; | |
1343 | ||
1344 | let mut multi_sugg_vec = vec![(lifetime_ref.span.shrink_to_hi(), "'a ".to_owned())]; | |
1345 | ||
1346 | if let Some(new_tuple) = new_param_sugg_tuple{ | |
1347 | multi_sugg_vec.push(new_tuple); | |
1348 | } | |
1349 | ||
1350 | diag.span_label(lifetime_ref.span, "expected named lifetime parameter"); | |
1351 | diag.multipart_suggestion("consider introducing a named lifetime parameter", | |
1352 | multi_sugg_vec, | |
1353 | rustc_errors::Applicability::MaybeIncorrect); | |
1354 | ||
1355 | }, | |
1356 | None => { } | |
1357 | } | |
1358 | ||
1359 | diag.emit(); | |
064997fb FG |
1360 | return; |
1361 | } | |
dfeec247 XL |
1362 | scope = s; |
1363 | } | |
1364 | ||
cdc7bbd5 XL |
1365 | Scope::Elision { s, .. } |
1366 | | Scope::ObjectLifetimeDefault { s, .. } | |
1367 | | Scope::Supertrait { s, .. } | |
1368 | | Scope::TraitRefBoundary { s, .. } => { | |
dfeec247 XL |
1369 | scope = s; |
1370 | } | |
1371 | } | |
1372 | }; | |
1373 | ||
1374 | if let Some(mut def) = result { | |
1375 | if let Region::EarlyBound(..) = def { | |
1376 | // Do not free early-bound regions, only late-bound ones. | |
1377 | } else if let Some(body_id) = outermost_body { | |
1378 | let fn_id = self.tcx.hir().body_owner(body_id); | |
1379 | match self.tcx.hir().get(fn_id) { | |
1380 | Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. }) | |
1381 | | Node::TraitItem(&hir::TraitItem { | |
ba9703b0 | 1382 | kind: hir::TraitItemKind::Fn(..), .. |
dfeec247 | 1383 | }) |
ba9703b0 | 1384 | | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => { |
dfeec247 | 1385 | let scope = self.tcx.hir().local_def_id(fn_id); |
f9f354fc | 1386 | def = Region::Free(scope.to_def_id(), def.id().unwrap()); |
dfeec247 XL |
1387 | } |
1388 | _ => {} | |
1389 | } | |
1390 | } | |
1391 | ||
dfeec247 | 1392 | self.insert_lifetime(lifetime_ref, def); |
04454e1e FG |
1393 | return; |
1394 | } | |
1395 | ||
f2b60f7d | 1396 | // We may fail to resolve higher-ranked lifetimes that are mentioned by APIT. |
04454e1e FG |
1397 | // AST-based resolution does not care for impl-trait desugaring, which are the |
1398 | // responibility of lowering. This may create a mismatch between the resolution | |
1399 | // AST found (`region_def_id`) which points to HRTB, and what HIR allows. | |
1400 | // ``` | |
1401 | // fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {} | |
1402 | // ``` | |
1403 | // | |
1404 | // In such case, walk back the binders to diagnose it properly. | |
1405 | let mut scope = self.scope; | |
1406 | loop { | |
1407 | match *scope { | |
1408 | Scope::Binder { | |
1409 | where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), .. | |
1410 | } => { | |
923072b8 FG |
1411 | let mut err = self.tcx.sess.struct_span_err( |
1412 | lifetime_ref.span, | |
1413 | "`impl Trait` can only mention lifetimes bound at the fn or impl level", | |
1414 | ); | |
1415 | err.span_note(self.tcx.def_span(region_def_id), "lifetime declared here"); | |
1416 | err.emit(); | |
04454e1e FG |
1417 | return; |
1418 | } | |
1419 | Scope::Root => break, | |
1420 | Scope::Binder { s, .. } | |
1421 | | Scope::Body { s, .. } | |
1422 | | Scope::Elision { s, .. } | |
1423 | | Scope::ObjectLifetimeDefault { s, .. } | |
1424 | | Scope::Supertrait { s, .. } | |
1425 | | Scope::TraitRefBoundary { s, .. } => { | |
1426 | scope = s; | |
1427 | } | |
1428 | } | |
dfeec247 | 1429 | } |
04454e1e FG |
1430 | |
1431 | self.tcx.sess.delay_span_bug( | |
1432 | lifetime_ref.span, | |
1433 | &format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,), | |
1434 | ); | |
dfeec247 XL |
1435 | } |
1436 | ||
f2b60f7d | 1437 | #[instrument(level = "debug", skip(self))] |
dfeec247 XL |
1438 | fn visit_segment_args( |
1439 | &mut self, | |
1440 | res: Res, | |
1441 | depth: usize, | |
1442 | generic_args: &'tcx hir::GenericArgs<'tcx>, | |
1443 | ) { | |
dfeec247 | 1444 | if generic_args.parenthesized { |
064997fb FG |
1445 | self.visit_fn_like_elision( |
1446 | generic_args.inputs(), | |
1447 | Some(generic_args.bindings[0].ty()), | |
1448 | false, | |
1449 | ); | |
dfeec247 XL |
1450 | return; |
1451 | } | |
1452 | ||
064997fb FG |
1453 | for arg in generic_args.args { |
1454 | if let hir::GenericArg::Lifetime(lt) = arg { | |
1455 | self.visit_lifetime(lt); | |
1456 | } | |
dfeec247 XL |
1457 | } |
1458 | ||
1459 | // Figure out if this is a type/trait segment, | |
1460 | // which requires object lifetime defaults. | |
dfeec247 | 1461 | let type_def_id = match res { |
f2b60f7d FG |
1462 | Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(self.tcx.parent(def_id)), |
1463 | Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(self.tcx.parent(def_id)), | |
ba9703b0 XL |
1464 | Res::Def( |
1465 | DefKind::Struct | |
1466 | | DefKind::Union | |
1467 | | DefKind::Enum | |
1468 | | DefKind::TyAlias | |
1469 | | DefKind::Trait, | |
1470 | def_id, | |
1471 | ) if depth == 0 => Some(def_id), | |
dfeec247 XL |
1472 | _ => None, |
1473 | }; | |
1474 | ||
f2b60f7d | 1475 | debug!(?type_def_id); |
dfeec247 XL |
1476 | |
1477 | // Compute a vector of defaults, one for each type parameter, | |
1478 | // per the rules given in RFCs 599 and 1156. Example: | |
1479 | // | |
1480 | // ```rust | |
1481 | // struct Foo<'a, T: 'a, U> { } | |
1482 | // ``` | |
1483 | // | |
1484 | // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default | |
1485 | // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) | |
1486 | // and `dyn Baz` to `dyn Baz + 'static` (because there is no | |
1487 | // such bound). | |
1488 | // | |
1489 | // Therefore, we would compute `object_lifetime_defaults` to a | |
1490 | // vector like `['x, 'static]`. Note that the vector only | |
1491 | // includes type parameters. | |
6a06907d | 1492 | let object_lifetime_defaults = type_def_id.map_or_else(Vec::new, |def_id| { |
dfeec247 XL |
1493 | let in_body = { |
1494 | let mut scope = self.scope; | |
1495 | loop { | |
1496 | match *scope { | |
1497 | Scope::Root => break false, | |
1498 | ||
1499 | Scope::Body { .. } => break true, | |
1500 | ||
1501 | Scope::Binder { s, .. } | |
1502 | | Scope::Elision { s, .. } | |
cdc7bbd5 XL |
1503 | | Scope::ObjectLifetimeDefault { s, .. } |
1504 | | Scope::Supertrait { s, .. } | |
1505 | | Scope::TraitRefBoundary { s, .. } => { | |
dfeec247 XL |
1506 | scope = s; |
1507 | } | |
1508 | } | |
1509 | } | |
1510 | }; | |
1511 | ||
1512 | let map = &self.map; | |
f2b60f7d FG |
1513 | let generics = self.tcx.generics_of(def_id); |
1514 | ||
1515 | // `type_def_id` points to an item, so there is nothing to inherit generics from. | |
1516 | debug_assert_eq!(generics.parent_count, 0); | |
1517 | ||
1518 | let set_to_region = |set: ObjectLifetimeDefault| match set { | |
1519 | ObjectLifetimeDefault::Empty => { | |
cdc7bbd5 XL |
1520 | if in_body { |
1521 | None | |
1522 | } else { | |
1523 | Some(Region::Static) | |
1524 | } | |
1525 | } | |
f2b60f7d FG |
1526 | ObjectLifetimeDefault::Static => Some(Region::Static), |
1527 | ObjectLifetimeDefault::Param(param_def_id) => { | |
1528 | // This index can be used with `generic_args` since `parent_count == 0`. | |
1529 | let index = generics.param_def_id_to_index[¶m_def_id] as usize; | |
1530 | generic_args.args.get(index).and_then(|arg| match arg { | |
1531 | GenericArg::Lifetime(lt) => map.defs.get(<.hir_id).copied(), | |
cdc7bbd5 | 1532 | _ => None, |
f2b60f7d | 1533 | }) |
cdc7bbd5 | 1534 | } |
f2b60f7d | 1535 | ObjectLifetimeDefault::Ambiguous => None, |
cdc7bbd5 | 1536 | }; |
f2b60f7d FG |
1537 | generics |
1538 | .params | |
1539 | .iter() | |
1540 | .filter_map(|param| { | |
1541 | match self.tcx.def_kind(param.def_id) { | |
1542 | // Generic consts don't impose any constraints. | |
1543 | // | |
1544 | // We still store a dummy value here to allow generic parameters | |
1545 | // in an arbitrary order. | |
1546 | DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty), | |
1547 | DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)), | |
1548 | // We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter | |
1549 | // works. Ignore it because it can't have a meaningful lifetime default. | |
1550 | DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None, | |
1551 | dk => bug!("unexpected def_kind {:?}", dk), | |
1552 | } | |
1553 | }) | |
1554 | .map(set_to_region) | |
1555 | .collect() | |
dfeec247 XL |
1556 | }); |
1557 | ||
f2b60f7d | 1558 | debug!(?object_lifetime_defaults); |
dfeec247 XL |
1559 | |
1560 | let mut i = 0; | |
1561 | for arg in generic_args.args { | |
1562 | match arg { | |
1563 | GenericArg::Lifetime(_) => {} | |
1564 | GenericArg::Type(ty) => { | |
1565 | if let Some(<) = object_lifetime_defaults.get(i) { | |
1566 | let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; | |
923072b8 | 1567 | self.with(scope, |this| this.visit_ty(ty)); |
dfeec247 XL |
1568 | } else { |
1569 | self.visit_ty(ty); | |
1570 | } | |
1571 | i += 1; | |
1572 | } | |
1573 | GenericArg::Const(ct) => { | |
1574 | self.visit_anon_const(&ct.value); | |
a2a8927a | 1575 | i += 1; |
dfeec247 | 1576 | } |
94222f64 XL |
1577 | GenericArg::Infer(inf) => { |
1578 | self.visit_id(inf.hir_id); | |
a2a8927a | 1579 | i += 1; |
94222f64 | 1580 | } |
dfeec247 XL |
1581 | } |
1582 | } | |
1583 | ||
1584 | // Hack: when resolving the type `XX` in binding like `dyn | |
1585 | // Foo<'b, Item = XX>`, the current object-lifetime default | |
1586 | // would be to examine the trait `Foo` to check whether it has | |
1587 | // a lifetime bound declared on `Item`. e.g., if `Foo` is | |
1588 | // declared like so, then the default object lifetime bound in | |
1589 | // `XX` should be `'b`: | |
1590 | // | |
1591 | // ```rust | |
1592 | // trait Foo<'a> { | |
1593 | // type Item: 'a; | |
1594 | // } | |
1595 | // ``` | |
1596 | // | |
1597 | // but if we just have `type Item;`, then it would be | |
1598 | // `'static`. However, we don't get all of this logic correct. | |
1599 | // | |
1600 | // Instead, we do something hacky: if there are no lifetime parameters | |
1601 | // to the trait, then we simply use a default object lifetime | |
1602 | // bound of `'static`, because there is no other possibility. On the other hand, | |
1603 | // if there ARE lifetime parameters, then we require the user to give an | |
1604 | // explicit bound for now. | |
1605 | // | |
1606 | // This is intended to leave room for us to implement the | |
1607 | // correct behavior in the future. | |
29967ef6 XL |
1608 | let has_lifetime_parameter = |
1609 | generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))); | |
dfeec247 | 1610 | |
cdc7bbd5 XL |
1611 | // Resolve lifetimes found in the bindings, so either in the type `XX` in `Item = XX` or |
1612 | // in the trait ref `YY<...>` in `Item: YY<...>`. | |
1613 | for binding in generic_args.bindings { | |
dfeec247 XL |
1614 | let scope = Scope::ObjectLifetimeDefault { |
1615 | lifetime: if has_lifetime_parameter { None } else { Some(Region::Static) }, | |
1616 | s: self.scope, | |
1617 | }; | |
cdc7bbd5 XL |
1618 | if let Some(type_def_id) = type_def_id { |
1619 | let lifetimes = LifetimeContext::supertrait_hrtb_lifetimes( | |
1620 | self.tcx, | |
1621 | type_def_id, | |
1622 | binding.ident, | |
1623 | ); | |
923072b8 | 1624 | self.with(scope, |this| { |
94222f64 XL |
1625 | let scope = Scope::Supertrait { |
1626 | lifetimes: lifetimes.unwrap_or_default(), | |
1627 | s: this.scope, | |
1628 | }; | |
923072b8 | 1629 | this.with(scope, |this| this.visit_assoc_type_binding(binding)); |
cdc7bbd5 XL |
1630 | }); |
1631 | } else { | |
923072b8 | 1632 | self.with(scope, |this| this.visit_assoc_type_binding(binding)); |
cdc7bbd5 XL |
1633 | } |
1634 | } | |
1635 | } | |
1636 | ||
1637 | /// Returns all the late-bound vars that come into scope from supertrait HRTBs, based on the | |
1638 | /// associated type name and starting trait. | |
1639 | /// For example, imagine we have | |
04454e1e | 1640 | /// ```ignore (illustrative) |
cdc7bbd5 XL |
1641 | /// trait Foo<'a, 'b> { |
1642 | /// type As; | |
1643 | /// } | |
1644 | /// trait Bar<'b>: for<'a> Foo<'a, 'b> {} | |
1645 | /// trait Bar: for<'b> Bar<'b> {} | |
1646 | /// ``` | |
1647 | /// In this case, if we wanted to the supertrait HRTB lifetimes for `As` on | |
1648 | /// the starting trait `Bar`, we would return `Some(['b, 'a])`. | |
1649 | fn supertrait_hrtb_lifetimes( | |
1650 | tcx: TyCtxt<'tcx>, | |
1651 | def_id: DefId, | |
1652 | assoc_name: Ident, | |
1653 | ) -> Option<Vec<ty::BoundVariableKind>> { | |
1654 | let trait_defines_associated_type_named = |trait_def_id: DefId| { | |
1655 | tcx.associated_items(trait_def_id) | |
1656 | .find_by_name_and_kind(tcx, assoc_name, ty::AssocKind::Type, trait_def_id) | |
1657 | .is_some() | |
1658 | }; | |
1659 | ||
1660 | use smallvec::{smallvec, SmallVec}; | |
1661 | let mut stack: SmallVec<[(DefId, SmallVec<[ty::BoundVariableKind; 8]>); 8]> = | |
1662 | smallvec![(def_id, smallvec![])]; | |
1663 | let mut visited: FxHashSet<DefId> = FxHashSet::default(); | |
1664 | loop { | |
5e7ed085 FG |
1665 | let Some((def_id, bound_vars)) = stack.pop() else { |
1666 | break None; | |
cdc7bbd5 XL |
1667 | }; |
1668 | // See issue #83753. If someone writes an associated type on a non-trait, just treat it as | |
1669 | // there being no supertrait HRTBs. | |
1670 | match tcx.def_kind(def_id) { | |
1671 | DefKind::Trait | DefKind::TraitAlias | DefKind::Impl => {} | |
1672 | _ => break None, | |
1673 | } | |
1674 | ||
1675 | if trait_defines_associated_type_named(def_id) { | |
1676 | break Some(bound_vars.into_iter().collect()); | |
1677 | } | |
1678 | let predicates = | |
1679 | tcx.super_predicates_that_define_assoc_type((def_id, Some(assoc_name))); | |
1680 | let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { | |
1681 | let bound_predicate = pred.kind(); | |
1682 | match bound_predicate.skip_binder() { | |
94222f64 | 1683 | ty::PredicateKind::Trait(data) => { |
cdc7bbd5 XL |
1684 | // The order here needs to match what we would get from `subst_supertrait` |
1685 | let pred_bound_vars = bound_predicate.bound_vars(); | |
1686 | let mut all_bound_vars = bound_vars.clone(); | |
1687 | all_bound_vars.extend(pred_bound_vars.iter()); | |
1688 | let super_def_id = data.trait_ref.def_id; | |
1689 | Some((super_def_id, all_bound_vars)) | |
1690 | } | |
1691 | _ => None, | |
1692 | } | |
1693 | }); | |
1694 | ||
1695 | let obligations = obligations.filter(|o| visited.insert(o.0)); | |
1696 | stack.extend(obligations); | |
dfeec247 XL |
1697 | } |
1698 | } | |
1699 | ||
f2b60f7d | 1700 | #[instrument(level = "debug", skip(self))] |
dfeec247 XL |
1701 | fn visit_fn_like_elision( |
1702 | &mut self, | |
1703 | inputs: &'tcx [hir::Ty<'tcx>], | |
1704 | output: Option<&'tcx hir::Ty<'tcx>>, | |
064997fb | 1705 | in_closure: bool, |
dfeec247 | 1706 | ) { |
064997fb | 1707 | self.with(Scope::Elision { s: self.scope }, |this| { |
dfeec247 XL |
1708 | for input in inputs { |
1709 | this.visit_ty(input); | |
1710 | } | |
064997fb FG |
1711 | if !in_closure && let Some(output) = output { |
1712 | this.visit_ty(output); | |
dfeec247 | 1713 | } |
064997fb FG |
1714 | }); |
1715 | if in_closure && let Some(output) = output { | |
1716 | self.visit_ty(output); | |
dfeec247 | 1717 | } |
dfeec247 XL |
1718 | } |
1719 | ||
dfeec247 XL |
1720 | fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { |
1721 | debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref); | |
1722 | let mut late_depth = 0; | |
1723 | let mut scope = self.scope; | |
1724 | let lifetime = loop { | |
1725 | match *scope { | |
cdc7bbd5 XL |
1726 | Scope::Binder { s, scope_type, .. } => { |
1727 | match scope_type { | |
1728 | BinderScopeType::Normal => late_depth += 1, | |
1729 | BinderScopeType::Concatenating => {} | |
1730 | } | |
dfeec247 XL |
1731 | scope = s; |
1732 | } | |
1733 | ||
1734 | Scope::Root | Scope::Elision { .. } => break Region::Static, | |
1735 | ||
1736 | Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, | |
1737 | ||
1738 | Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, | |
cdc7bbd5 XL |
1739 | |
1740 | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { | |
1741 | scope = s; | |
1742 | } | |
dfeec247 XL |
1743 | } |
1744 | }; | |
1745 | self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); | |
1746 | } | |
1747 | ||
f2b60f7d | 1748 | #[instrument(level = "debug", skip(self))] |
dfeec247 | 1749 | fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { |
dfeec247 | 1750 | debug!( |
cdc7bbd5 | 1751 | node = ?self.tcx.hir().node_to_string(lifetime_ref.hir_id), |
17df50a5 | 1752 | span = ?self.tcx.sess.source_map().span_to_diagnostic_string(lifetime_ref.span) |
dfeec247 XL |
1753 | ); |
1754 | self.map.defs.insert(lifetime_ref.hir_id, def); | |
dfeec247 XL |
1755 | } |
1756 | ||
1757 | /// Sometimes we resolve a lifetime, but later find that it is an | |
1758 | /// error (esp. around impl trait). In that case, we remove the | |
1759 | /// entry into `map.defs` so as not to confuse later code. | |
1760 | fn uninsert_lifetime_on_error(&mut self, lifetime_ref: &'tcx hir::Lifetime, bad_def: Region) { | |
1761 | let old_value = self.map.defs.remove(&lifetime_ref.hir_id); | |
1762 | assert_eq!(old_value, Some(bad_def)); | |
1763 | } | |
1764 | } | |
1765 | ||
1766 | /// Detects late-bound lifetimes and inserts them into | |
923072b8 | 1767 | /// `late_bound`. |
dfeec247 XL |
1768 | /// |
1769 | /// A region declared on a fn is **late-bound** if: | |
1770 | /// - it is constrained by an argument type; | |
1771 | /// - it does not appear in a where-clause. | |
1772 | /// | |
1773 | /// "Constrained" basically means that it appears in any type but | |
1774 | /// not amongst the inputs to a projection. In other words, `<&'a | |
1775 | /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. | |
923072b8 FG |
1776 | fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<LocalDefId>> { |
1777 | let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); | |
1778 | let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?; | |
1779 | let generics = tcx.hir().get_generics(def_id)?; | |
1780 | ||
1781 | let mut late_bound = FxIndexSet::default(); | |
1782 | ||
dfeec247 XL |
1783 | let mut constrained_by_input = ConstrainedCollector::default(); |
1784 | for arg_ty in decl.inputs { | |
1785 | constrained_by_input.visit_ty(arg_ty); | |
1786 | } | |
1787 | ||
1788 | let mut appears_in_output = AllCollector::default(); | |
1789 | intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); | |
1790 | ||
cdc7bbd5 | 1791 | debug!(?constrained_by_input.regions); |
dfeec247 XL |
1792 | |
1793 | // Walk the lifetimes that appear in where clauses. | |
1794 | // | |
1795 | // Subtle point: because we disallow nested bindings, we can just | |
1796 | // ignore binders here and scrape up all names we see. | |
1797 | let mut appears_in_where_clause = AllCollector::default(); | |
1798 | appears_in_where_clause.visit_generics(generics); | |
cdc7bbd5 | 1799 | debug!(?appears_in_where_clause.regions); |
dfeec247 XL |
1800 | |
1801 | // Late bound regions are those that: | |
1802 | // - appear in the inputs | |
1803 | // - do not appear in the where-clauses | |
1804 | // - are not implicitly captured by `impl Trait` | |
1805 | for param in generics.params { | |
1806 | match param.kind { | |
1807 | hir::GenericParamKind::Lifetime { .. } => { /* fall through */ } | |
1808 | ||
1809 | // Neither types nor consts are late-bound. | |
1810 | hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue, | |
1811 | } | |
1812 | ||
923072b8 FG |
1813 | let param_def_id = tcx.hir().local_def_id(param.hir_id); |
1814 | ||
dfeec247 | 1815 | // appears in the where clauses? early-bound. |
923072b8 | 1816 | if appears_in_where_clause.regions.contains(¶m_def_id) { |
dfeec247 XL |
1817 | continue; |
1818 | } | |
1819 | ||
1820 | // does not appear in the inputs, but appears in the return type? early-bound. | |
923072b8 FG |
1821 | if !constrained_by_input.regions.contains(¶m_def_id) |
1822 | && appears_in_output.regions.contains(¶m_def_id) | |
dfeec247 XL |
1823 | { |
1824 | continue; | |
1825 | } | |
1826 | ||
cdc7bbd5 | 1827 | debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id); |
dfeec247 | 1828 | |
923072b8 | 1829 | let inserted = late_bound.insert(param_def_id); |
dfeec247 XL |
1830 | assert!(inserted, "visited lifetime {:?} twice", param.hir_id); |
1831 | } | |
1832 | ||
923072b8 FG |
1833 | debug!(?late_bound); |
1834 | return Some(tcx.arena.alloc(late_bound)); | |
dfeec247 XL |
1835 | |
1836 | #[derive(Default)] | |
1837 | struct ConstrainedCollector { | |
923072b8 | 1838 | regions: FxHashSet<LocalDefId>, |
dfeec247 XL |
1839 | } |
1840 | ||
1841 | impl<'v> Visitor<'v> for ConstrainedCollector { | |
dfeec247 XL |
1842 | fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { |
1843 | match ty.kind { | |
ba9703b0 XL |
1844 | hir::TyKind::Path( |
1845 | hir::QPath::Resolved(Some(_), _) | hir::QPath::TypeRelative(..), | |
1846 | ) => { | |
dfeec247 XL |
1847 | // ignore lifetimes appearing in associated type |
1848 | // projections, as they are not *constrained* | |
1849 | // (defined above) | |
1850 | } | |
1851 | ||
1852 | hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { | |
1853 | // consider only the lifetimes on the final | |
1854 | // segment; I am not sure it's even currently | |
1855 | // valid to have them elsewhere, but even if it | |
1856 | // is, those would be potentially inputs to | |
1857 | // projections | |
1858 | if let Some(last_segment) = path.segments.last() { | |
f2b60f7d | 1859 | self.visit_path_segment(last_segment); |
dfeec247 XL |
1860 | } |
1861 | } | |
1862 | ||
1863 | _ => { | |
1864 | intravisit::walk_ty(self, ty); | |
1865 | } | |
1866 | } | |
1867 | } | |
1868 | ||
1869 | fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { | |
923072b8 FG |
1870 | if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name { |
1871 | self.regions.insert(def_id); | |
1872 | } | |
dfeec247 XL |
1873 | } |
1874 | } | |
1875 | ||
1876 | #[derive(Default)] | |
1877 | struct AllCollector { | |
923072b8 | 1878 | regions: FxHashSet<LocalDefId>, |
dfeec247 XL |
1879 | } |
1880 | ||
1881 | impl<'v> Visitor<'v> for AllCollector { | |
dfeec247 | 1882 | fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { |
923072b8 FG |
1883 | if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name { |
1884 | self.regions.insert(def_id); | |
1885 | } | |
dfeec247 XL |
1886 | } |
1887 | } | |
1888 | } |