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