]>
Commit | Line | Data |
---|---|---|
cdc7bbd5 | 1 | // ignore-tidy-filelength |
dfeec247 XL |
2 | //! Name resolution for lifetimes. |
3 | //! | |
4 | //! Name resolution for lifetimes follows *much* simpler rules than the | |
5 | //! full resolve. For example, lifetime names are never exported or | |
6 | //! used between functions, and they operate in a purely top-down | |
7 | //! way. Therefore, we break lifetime name resolution into a separate pass. | |
8 | ||
74b04a01 | 9 | use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; |
74b04a01 | 10 | use rustc_ast::walk_list; |
17df50a5 | 11 | use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; |
dfeec247 XL |
12 | use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; |
13 | use rustc_hir as hir; | |
14 | use rustc_hir::def::{DefKind, Res}; | |
17df50a5 | 15 | use rustc_hir::def_id::{DefIdMap, LocalDefId}; |
5869c6ff | 16 | use rustc_hir::hir_id::ItemLocalId; |
dfeec247 XL |
17 | use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; |
18 | use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath}; | |
19 | use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind}; | |
ba9703b0 XL |
20 | use rustc_middle::hir::map::Map; |
21 | use rustc_middle::middle::resolve_lifetime::*; | |
22 | use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; | |
23 | use rustc_middle::{bug, span_bug}; | |
24 | use rustc_session::lint; | |
17df50a5 | 25 | use rustc_span::def_id::DefId; |
f9f354fc | 26 | use rustc_span::symbol::{kw, sym, Ident, Symbol}; |
dfeec247 XL |
27 | use rustc_span::Span; |
28 | use std::borrow::Cow; | |
29 | use std::cell::Cell; | |
cdc7bbd5 | 30 | use std::fmt; |
f9f354fc | 31 | use std::mem::take; |
dfeec247 | 32 | |
cdc7bbd5 | 33 | use tracing::{debug, span, Level}; |
dfeec247 XL |
34 | |
35 | // This counts the no of times a lifetime is used | |
36 | #[derive(Clone, Copy, Debug)] | |
37 | pub enum LifetimeUseSet<'tcx> { | |
38 | One(&'tcx hir::Lifetime), | |
39 | Many, | |
40 | } | |
41 | ||
42 | trait RegionExt { | |
43 | fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region); | |
44 | ||
cdc7bbd5 | 45 | fn late(index: u32, hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region); |
dfeec247 | 46 | |
cdc7bbd5 | 47 | fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region; |
dfeec247 XL |
48 | |
49 | fn id(&self) -> Option<DefId>; | |
50 | ||
51 | fn shifted(self, amount: u32) -> Region; | |
52 | ||
53 | fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region; | |
54 | ||
55 | fn subst<'a, L>(self, params: L, map: &NamedRegionMap) -> Option<Region> | |
56 | where | |
57 | L: Iterator<Item = &'a hir::Lifetime>; | |
58 | } | |
59 | ||
60 | impl RegionExt for Region { | |
61 | fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) { | |
62 | let i = *index; | |
63 | *index += 1; | |
64 | let def_id = hir_map.local_def_id(param.hir_id); | |
65 | let origin = LifetimeDefOrigin::from_param(param); | |
66 | debug!("Region::early: index={} def_id={:?}", i, def_id); | |
f9f354fc | 67 | (param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id(), origin)) |
dfeec247 XL |
68 | } |
69 | ||
cdc7bbd5 | 70 | fn late(idx: u32, hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) { |
dfeec247 XL |
71 | let depth = ty::INNERMOST; |
72 | let def_id = hir_map.local_def_id(param.hir_id); | |
73 | let origin = LifetimeDefOrigin::from_param(param); | |
74 | debug!( | |
cdc7bbd5 XL |
75 | "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?} origin={:?}", |
76 | idx, param, depth, def_id, origin, | |
dfeec247 | 77 | ); |
cdc7bbd5 XL |
78 | ( |
79 | param.name.normalize_to_macros_2_0(), | |
80 | Region::LateBound(depth, idx, def_id.to_def_id(), origin), | |
81 | ) | |
dfeec247 XL |
82 | } |
83 | ||
cdc7bbd5 | 84 | fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region { |
dfeec247 XL |
85 | let i = index.get(); |
86 | index.set(i + 1); | |
87 | let depth = ty::INNERMOST; | |
cdc7bbd5 | 88 | Region::LateBoundAnon(depth, named_late_bound_vars + i, i) |
dfeec247 XL |
89 | } |
90 | ||
91 | fn id(&self) -> Option<DefId> { | |
92 | match *self { | |
93 | Region::Static | Region::LateBoundAnon(..) => None, | |
94 | ||
cdc7bbd5 | 95 | Region::EarlyBound(_, id, _) | Region::LateBound(_, _, id, _) | Region::Free(_, id) => { |
dfeec247 XL |
96 | Some(id) |
97 | } | |
98 | } | |
99 | } | |
100 | ||
101 | fn shifted(self, amount: u32) -> Region { | |
102 | match self { | |
cdc7bbd5 XL |
103 | Region::LateBound(debruijn, idx, id, origin) => { |
104 | Region::LateBound(debruijn.shifted_in(amount), idx, id, origin) | |
dfeec247 | 105 | } |
cdc7bbd5 XL |
106 | Region::LateBoundAnon(debruijn, index, anon_index) => { |
107 | Region::LateBoundAnon(debruijn.shifted_in(amount), index, anon_index) | |
dfeec247 XL |
108 | } |
109 | _ => self, | |
110 | } | |
111 | } | |
112 | ||
113 | fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region { | |
114 | match self { | |
cdc7bbd5 XL |
115 | Region::LateBound(debruijn, index, id, origin) => { |
116 | Region::LateBound(debruijn.shifted_out_to_binder(binder), index, id, origin) | |
dfeec247 | 117 | } |
cdc7bbd5 XL |
118 | Region::LateBoundAnon(debruijn, index, anon_index) => { |
119 | Region::LateBoundAnon(debruijn.shifted_out_to_binder(binder), index, anon_index) | |
dfeec247 XL |
120 | } |
121 | _ => self, | |
122 | } | |
123 | } | |
124 | ||
125 | fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option<Region> | |
126 | where | |
127 | L: Iterator<Item = &'a hir::Lifetime>, | |
128 | { | |
129 | if let Region::EarlyBound(index, _, _) = self { | |
130 | params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned()) | |
131 | } else { | |
132 | Some(self) | |
133 | } | |
134 | } | |
135 | } | |
136 | ||
137 | /// Maps the id of each lifetime reference to the lifetime decl | |
138 | /// that it corresponds to. | |
139 | /// | |
140 | /// FIXME. This struct gets converted to a `ResolveLifetimes` for | |
ba9703b0 | 141 | /// actual use. It has the same data, but indexed by `LocalDefId`. This |
dfeec247 | 142 | /// is silly. |
cdc7bbd5 | 143 | #[derive(Debug, Default)] |
dfeec247 XL |
144 | struct NamedRegionMap { |
145 | // maps from every use of a named (not anonymous) lifetime to a | |
146 | // `Region` describing how that region is bound | |
147 | defs: HirIdMap<Region>, | |
148 | ||
149 | // the set of lifetime def ids that are late-bound; a region can | |
150 | // be late-bound if (a) it does NOT appear in a where-clause and | |
151 | // (b) it DOES appear in the arguments. | |
152 | late_bound: HirIdSet, | |
153 | ||
cdc7bbd5 XL |
154 | // Maps relevant hir items to the bound vars on them. These include: |
155 | // - function defs | |
156 | // - function pointers | |
157 | // - closures | |
158 | // - trait refs | |
159 | // - bound types (like `T` in `for<'a> T<'a>: Foo`) | |
160 | late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>, | |
17df50a5 XL |
161 | |
162 | // maps `PathSegment` `HirId`s to lifetime scopes. | |
163 | scope_for_path: Option<FxHashMap<LocalDefId, FxHashMap<ItemLocalId, LifetimeScopeForPath>>>, | |
dfeec247 XL |
164 | } |
165 | ||
74b04a01 XL |
166 | crate struct LifetimeContext<'a, 'tcx> { |
167 | crate tcx: TyCtxt<'tcx>, | |
dfeec247 XL |
168 | map: &'a mut NamedRegionMap, |
169 | scope: ScopeRef<'a>, | |
170 | ||
dfeec247 XL |
171 | /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax. |
172 | is_in_fn_syntax: bool, | |
173 | ||
3dfed10e XL |
174 | is_in_const_generic: bool, |
175 | ||
cdc7bbd5 XL |
176 | /// Indicates that we only care about the definition of a trait. This should |
177 | /// be false if the `Item` we are resolving lifetimes for is not a trait or | |
178 | /// we eventually need lifetimes resolve for trait items. | |
179 | trait_definition_only: bool, | |
180 | ||
dfeec247 | 181 | /// List of labels in the function/method currently under analysis. |
f9f354fc | 182 | labels_in_fn: Vec<Ident>, |
dfeec247 XL |
183 | |
184 | /// Cache for cross-crate per-definition object lifetime defaults. | |
185 | xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>, | |
186 | ||
187 | lifetime_uses: &'a mut DefIdMap<LifetimeUseSet<'tcx>>, | |
188 | ||
189 | /// When encountering an undefined named lifetime, we will suggest introducing it in these | |
190 | /// places. | |
74b04a01 | 191 | crate missing_named_lifetime_spots: Vec<MissingLifetimeSpot<'tcx>>, |
dfeec247 XL |
192 | } |
193 | ||
194 | #[derive(Debug)] | |
195 | enum Scope<'a> { | |
196 | /// Declares lifetimes, and each can be early-bound or late-bound. | |
197 | /// The `DebruijnIndex` of late-bound lifetimes starts at `1` and | |
198 | /// it should be shifted by the number of `Binder`s in between the | |
199 | /// declaration `Binder` and the location it's referenced from. | |
200 | Binder { | |
17df50a5 XL |
201 | /// We use an IndexMap here because we want these lifetimes in order |
202 | /// for diagnostics. | |
203 | lifetimes: FxIndexMap<hir::ParamName, Region>, | |
dfeec247 XL |
204 | |
205 | /// if we extend this scope with another scope, what is the next index | |
206 | /// we should use for an early-bound region? | |
207 | next_early_index: u32, | |
208 | ||
209 | /// Flag is set to true if, in this binder, `'_` would be | |
210 | /// equivalent to a "single-use region". This is true on | |
211 | /// impls, but not other kinds of items. | |
212 | track_lifetime_uses: bool, | |
213 | ||
214 | /// Whether or not this binder would serve as the parent | |
215 | /// binder for opaque types introduced within. For example: | |
216 | /// | |
217 | /// ```text | |
218 | /// fn foo<'a>() -> impl for<'b> Trait<Item = impl Trait2<'a>> | |
219 | /// ``` | |
220 | /// | |
221 | /// Here, the opaque types we create for the `impl Trait` | |
222 | /// and `impl Trait2` references will both have the `foo` item | |
223 | /// as their parent. When we get to `impl Trait2`, we find | |
224 | /// that it is nested within the `for<>` binder -- this flag | |
225 | /// allows us to skip that when looking for the parent binder | |
226 | /// of the resulting opaque type. | |
227 | opaque_type_parent: bool, | |
228 | ||
cdc7bbd5 XL |
229 | scope_type: BinderScopeType, |
230 | ||
231 | /// The late bound vars for a given item are stored by `HirId` to be | |
232 | /// queried later. However, if we enter an elision scope, we have to | |
233 | /// later append the elided bound vars to the list and need to know what | |
234 | /// to append to. | |
235 | hir_id: hir::HirId, | |
236 | ||
dfeec247 XL |
237 | s: ScopeRef<'a>, |
238 | }, | |
239 | ||
240 | /// Lifetimes introduced by a fn are scoped to the call-site for that fn, | |
241 | /// if this is a fn body, otherwise the original definitions are used. | |
242 | /// Unspecified lifetimes are inferred, unless an elision scope is nested, | |
243 | /// e.g., `(&T, fn(&T) -> &T);` becomes `(&'_ T, for<'a> fn(&'a T) -> &'a T)`. | |
244 | Body { | |
245 | id: hir::BodyId, | |
246 | s: ScopeRef<'a>, | |
247 | }, | |
248 | ||
249 | /// A scope which either determines unspecified lifetimes or errors | |
250 | /// on them (e.g., due to ambiguity). For more details, see `Elide`. | |
251 | Elision { | |
252 | elide: Elide, | |
253 | s: ScopeRef<'a>, | |
254 | }, | |
255 | ||
256 | /// Use a specific lifetime (if `Some`) or leave it unset (to be | |
257 | /// inferred in a function body or potentially error outside one), | |
258 | /// for the default choice of lifetime in a trait object type. | |
259 | ObjectLifetimeDefault { | |
260 | lifetime: Option<Region>, | |
261 | s: ScopeRef<'a>, | |
262 | }, | |
263 | ||
cdc7bbd5 XL |
264 | /// When we have nested trait refs, we concanetate late bound vars for inner |
265 | /// trait refs from outer ones. But we also need to include any HRTB | |
266 | /// lifetimes encountered when identifying the trait that an associated type | |
267 | /// is declared on. | |
268 | Supertrait { | |
269 | lifetimes: Vec<ty::BoundVariableKind>, | |
270 | s: ScopeRef<'a>, | |
271 | }, | |
272 | ||
273 | TraitRefBoundary { | |
274 | s: ScopeRef<'a>, | |
275 | }, | |
276 | ||
dfeec247 XL |
277 | Root, |
278 | } | |
279 | ||
cdc7bbd5 XL |
280 | #[derive(Copy, Clone, Debug)] |
281 | enum BinderScopeType { | |
282 | /// Any non-concatenating binder scopes. | |
283 | Normal, | |
284 | /// Within a syntactic trait ref, there may be multiple poly trait refs that | |
285 | /// are nested (under the `associcated_type_bounds` feature). The binders of | |
286 | /// the innner poly trait refs are extended from the outer poly trait refs | |
287 | /// and don't increase the late bound depth. If you had | |
288 | /// `T: for<'a> Foo<Bar: for<'b> Baz<'a, 'b>>`, then the `for<'b>` scope | |
289 | /// would be `Concatenating`. This also used in trait refs in where clauses | |
290 | /// where we have two binders `for<> T: for<> Foo` (I've intentionally left | |
291 | /// out any lifetimes because they aren't needed to show the two scopes). | |
292 | /// The inner `for<>` has a scope of `Concatenating`. | |
293 | Concatenating, | |
294 | } | |
295 | ||
296 | // A helper struct for debugging scopes without printing parent scopes | |
297 | struct TruncatedScopeDebug<'a>(&'a Scope<'a>); | |
298 | ||
299 | impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { | |
300 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
301 | match self.0 { | |
302 | Scope::Binder { | |
303 | lifetimes, | |
304 | next_early_index, | |
305 | track_lifetime_uses, | |
306 | opaque_type_parent, | |
307 | scope_type, | |
308 | hir_id, | |
309 | s: _, | |
310 | } => f | |
311 | .debug_struct("Binder") | |
312 | .field("lifetimes", lifetimes) | |
313 | .field("next_early_index", next_early_index) | |
314 | .field("track_lifetime_uses", track_lifetime_uses) | |
315 | .field("opaque_type_parent", opaque_type_parent) | |
316 | .field("scope_type", scope_type) | |
317 | .field("hir_id", hir_id) | |
318 | .field("s", &"..") | |
319 | .finish(), | |
320 | Scope::Body { id, s: _ } => { | |
321 | f.debug_struct("Body").field("id", id).field("s", &"..").finish() | |
322 | } | |
323 | Scope::Elision { elide, s: _ } => { | |
324 | f.debug_struct("Elision").field("elide", elide).field("s", &"..").finish() | |
325 | } | |
326 | Scope::ObjectLifetimeDefault { lifetime, s: _ } => f | |
327 | .debug_struct("ObjectLifetimeDefault") | |
328 | .field("lifetime", lifetime) | |
329 | .field("s", &"..") | |
330 | .finish(), | |
331 | Scope::Supertrait { lifetimes, s: _ } => f | |
332 | .debug_struct("Supertrait") | |
333 | .field("lifetimes", lifetimes) | |
334 | .field("s", &"..") | |
335 | .finish(), | |
336 | Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(), | |
337 | Scope::Root => f.debug_struct("Root").finish(), | |
338 | } | |
339 | } | |
340 | } | |
341 | ||
dfeec247 XL |
342 | #[derive(Clone, Debug)] |
343 | enum Elide { | |
344 | /// Use a fresh anonymous late-bound lifetime each time, by | |
cdc7bbd5 XL |
345 | /// incrementing the counter to generate sequential indices. All |
346 | /// anonymous lifetimes must start *after* named bound vars. | |
347 | FreshLateAnon(u32, Cell<u32>), | |
dfeec247 XL |
348 | /// Always use this one lifetime. |
349 | Exact(Region), | |
350 | /// Less or more than one lifetime were found, error on unspecified. | |
351 | Error(Vec<ElisionFailureInfo>), | |
f035d41b XL |
352 | /// Forbid lifetime elision inside of a larger scope where it would be |
353 | /// permitted. For example, in let position impl trait. | |
354 | Forbid, | |
dfeec247 XL |
355 | } |
356 | ||
357 | #[derive(Clone, Debug)] | |
74b04a01 | 358 | crate struct ElisionFailureInfo { |
dfeec247 XL |
359 | /// Where we can find the argument pattern. |
360 | parent: Option<hir::BodyId>, | |
361 | /// The index of the argument in the original definition. | |
362 | index: usize, | |
363 | lifetime_count: usize, | |
364 | have_bound_regions: bool, | |
74b04a01 | 365 | crate span: Span, |
dfeec247 XL |
366 | } |
367 | ||
368 | type ScopeRef<'a> = &'a Scope<'a>; | |
369 | ||
370 | const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; | |
371 | ||
f035d41b | 372 | pub fn provide(providers: &mut ty::query::Providers) { |
dfeec247 | 373 | *providers = ty::query::Providers { |
cdc7bbd5 | 374 | resolve_lifetimes_trait_definition, |
dfeec247 XL |
375 | resolve_lifetimes, |
376 | ||
cdc7bbd5 | 377 | named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id), |
5869c6ff | 378 | is_late_bound_map, |
dfeec247 | 379 | object_lifetime_defaults_map: |tcx, id| { |
cdc7bbd5 XL |
380 | let hir_id = tcx.hir().local_def_id_to_hir_id(id); |
381 | match tcx.hir().find(hir_id) { | |
382 | Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item), | |
383 | _ => None, | |
384 | } | |
dfeec247 | 385 | }, |
cdc7bbd5 | 386 | late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id), |
17df50a5 XL |
387 | lifetime_scope_map: |tcx, id| { |
388 | let item_id = item_for(tcx, id); | |
389 | do_resolve(tcx, item_id, false, true).scope_for_path.unwrap().remove(&id) | |
390 | }, | |
dfeec247 XL |
391 | |
392 | ..*providers | |
393 | }; | |
dfeec247 XL |
394 | } |
395 | ||
cdc7bbd5 XL |
396 | /// Like `resolve_lifetimes`, but does not resolve lifetimes for trait items. |
397 | /// Also does not generate any diagnostics. | |
398 | /// | |
399 | /// This is ultimately a subset of the `resolve_lifetimes` work. It effectively | |
400 | /// resolves lifetimes only within the trait "header" -- that is, the trait | |
401 | /// and supertrait list. In contrast, `resolve_lifetimes` resolves all the | |
402 | /// lifetimes within the trait and its items. There is room to refactor this, | |
403 | /// for example to resolve lifetimes for each trait item in separate queries, | |
404 | /// but it's convenient to do the entire trait at once because the lifetimes | |
405 | /// from the trait definition are in scope within the trait items as well. | |
406 | /// | |
407 | /// The reason for this separate call is to resolve what would otherwise | |
408 | /// be a cycle. Consider this example: | |
409 | /// | |
410 | /// ```rust | |
411 | /// trait Base<'a> { | |
412 | /// type BaseItem; | |
413 | /// } | |
414 | /// trait Sub<'b>: for<'a> Base<'a> { | |
415 | /// type SubItem: Sub<BaseItem = &'b u32>; | |
416 | /// } | |
417 | /// ``` | |
418 | /// | |
419 | /// When we resolve `Sub` and all its items, we also have to resolve `Sub<BaseItem = &'b u32>`. | |
420 | /// To figure out the index of `'b`, we have to know about the supertraits | |
421 | /// of `Sub` so that we can determine that the `for<'a>` will be in scope. | |
422 | /// (This is because we -- currently at least -- flatten all the late-bound | |
423 | /// lifetimes into a single binder.) This requires us to resolve the | |
424 | /// *trait definition* of `Sub`; basically just enough lifetime information | |
425 | /// to look at the supertraits. | |
426 | #[tracing::instrument(level = "debug", skip(tcx))] | |
427 | fn resolve_lifetimes_trait_definition( | |
428 | tcx: TyCtxt<'_>, | |
429 | local_def_id: LocalDefId, | |
430 | ) -> ResolveLifetimes { | |
17df50a5 | 431 | convert_named_region_map(do_resolve(tcx, local_def_id, true, false)) |
cdc7bbd5 | 432 | } |
dfeec247 | 433 | |
cdc7bbd5 XL |
434 | /// Computes the `ResolveLifetimes` map that contains data for an entire `Item`. |
435 | /// You should not read the result of this query directly, but rather use | |
436 | /// `named_region_map`, `is_late_bound_map`, etc. | |
437 | #[tracing::instrument(level = "debug", skip(tcx))] | |
438 | fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes { | |
17df50a5 | 439 | convert_named_region_map(do_resolve(tcx, local_def_id, false, false)) |
cdc7bbd5 XL |
440 | } |
441 | ||
442 | fn do_resolve( | |
443 | tcx: TyCtxt<'_>, | |
444 | local_def_id: LocalDefId, | |
445 | trait_definition_only: bool, | |
17df50a5 XL |
446 | with_scope_for_path: bool, |
447 | ) -> NamedRegionMap { | |
cdc7bbd5 XL |
448 | let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(local_def_id)); |
449 | let mut named_region_map = NamedRegionMap { | |
450 | defs: Default::default(), | |
451 | late_bound: Default::default(), | |
452 | late_bound_vars: Default::default(), | |
17df50a5 | 453 | scope_for_path: with_scope_for_path.then(|| Default::default()), |
cdc7bbd5 XL |
454 | }; |
455 | let mut visitor = LifetimeContext { | |
456 | tcx, | |
457 | map: &mut named_region_map, | |
458 | scope: ROOT_SCOPE, | |
459 | is_in_fn_syntax: false, | |
460 | is_in_const_generic: false, | |
461 | trait_definition_only, | |
462 | labels_in_fn: vec![], | |
463 | xcrate_object_lifetime_defaults: Default::default(), | |
464 | lifetime_uses: &mut Default::default(), | |
465 | missing_named_lifetime_spots: vec![], | |
466 | }; | |
467 | visitor.visit_item(item); | |
dfeec247 | 468 | |
17df50a5 XL |
469 | named_region_map |
470 | } | |
471 | ||
472 | fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetimes { | |
dfeec247 XL |
473 | let mut rl = ResolveLifetimes::default(); |
474 | ||
475 | for (hir_id, v) in named_region_map.defs { | |
ba9703b0 | 476 | let map = rl.defs.entry(hir_id.owner).or_default(); |
dfeec247 XL |
477 | map.insert(hir_id.local_id, v); |
478 | } | |
479 | for hir_id in named_region_map.late_bound { | |
ba9703b0 | 480 | let map = rl.late_bound.entry(hir_id.owner).or_default(); |
dfeec247 XL |
481 | map.insert(hir_id.local_id); |
482 | } | |
cdc7bbd5 XL |
483 | for (hir_id, v) in named_region_map.late_bound_vars { |
484 | let map = rl.late_bound_vars.entry(hir_id.owner).or_default(); | |
dfeec247 XL |
485 | map.insert(hir_id.local_id, v); |
486 | } | |
487 | ||
cdc7bbd5 | 488 | debug!(?rl.defs); |
f9f354fc | 489 | rl |
dfeec247 XL |
490 | } |
491 | ||
cdc7bbd5 XL |
492 | /// Given `any` owner (structs, traits, trait methods, etc.), does lifetime resolution. |
493 | /// There are two important things this does. | |
494 | /// First, we have to resolve lifetimes for | |
495 | /// the entire *`Item`* that contains this owner, because that's the largest "scope" | |
496 | /// where we can have relevant lifetimes. | |
497 | /// Second, if we are asking for lifetimes in a trait *definition*, we use `resolve_lifetimes_trait_definition` | |
498 | /// instead of `resolve_lifetimes`, which does not descend into the trait items and does not emit diagnostics. | |
499 | /// This allows us to avoid cycles. Importantly, if we ask for lifetimes for lifetimes that have an owner | |
500 | /// other than the trait itself (like the trait methods or associated types), then we just use the regular | |
501 | /// `resolve_lifetimes`. | |
502 | fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ResolveLifetimes { | |
503 | let item_id = item_for(tcx, def_id); | |
504 | if item_id == def_id { | |
505 | let item = tcx.hir().item(hir::ItemId { def_id: item_id }); | |
506 | match item.kind { | |
507 | hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(item_id), | |
508 | _ => tcx.resolve_lifetimes(item_id), | |
509 | } | |
510 | } else { | |
511 | tcx.resolve_lifetimes(item_id) | |
512 | } | |
513 | } | |
514 | ||
515 | /// Finds the `Item` that contains the given `LocalDefId` | |
516 | fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId { | |
517 | let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id); | |
518 | match tcx.hir().find(hir_id) { | |
519 | Some(Node::Item(item)) => { | |
520 | return item.def_id; | |
521 | } | |
522 | _ => {} | |
523 | } | |
524 | let item = { | |
c295e0f8 | 525 | let mut parent_iter = tcx.hir().parent_iter(hir_id); |
cdc7bbd5 XL |
526 | loop { |
527 | let node = parent_iter.next().map(|n| n.1); | |
528 | match node { | |
529 | Some(hir::Node::Item(item)) => break item.def_id, | |
530 | Some(hir::Node::Crate(_)) | None => bug!("Called `item_for` on an Item."), | |
531 | _ => {} | |
532 | } | |
533 | } | |
534 | }; | |
535 | item | |
536 | } | |
537 | ||
5869c6ff XL |
538 | fn is_late_bound_map<'tcx>( |
539 | tcx: TyCtxt<'tcx>, | |
540 | def_id: LocalDefId, | |
541 | ) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> { | |
542 | match tcx.def_kind(def_id) { | |
543 | DefKind::AnonConst => { | |
544 | let mut def_id = tcx | |
545 | .parent(def_id.to_def_id()) | |
546 | .unwrap_or_else(|| bug!("anon const or closure without a parent")); | |
547 | // We search for the next outer anon const or fn here | |
548 | // while skipping closures. | |
549 | // | |
550 | // Note that for `AnonConst` we still just recurse until we | |
551 | // find a function body, but who cares :shrug: | |
552 | while tcx.is_closure(def_id) { | |
553 | def_id = tcx | |
554 | .parent(def_id) | |
555 | .unwrap_or_else(|| bug!("anon const or closure without a parent")); | |
556 | } | |
557 | ||
558 | tcx.is_late_bound_map(def_id.expect_local()) | |
559 | } | |
cdc7bbd5 | 560 | _ => resolve_lifetimes_for(tcx, def_id).late_bound.get(&def_id).map(|lt| (def_id, lt)), |
5869c6ff XL |
561 | } |
562 | } | |
563 | ||
dfeec247 XL |
564 | /// In traits, there is an implicit `Self` type parameter which comes before the generics. |
565 | /// We have to account for this when computing the index of the other generic parameters. | |
566 | /// This function returns whether there is such an implicit parameter defined on the given item. | |
567 | fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool { | |
29967ef6 | 568 | matches!(*node, hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..)) |
dfeec247 XL |
569 | } |
570 | ||
cdc7bbd5 XL |
571 | fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind { |
572 | match region { | |
573 | Region::LateBound(_, _, def_id, _) => { | |
574 | let name = tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local())); | |
575 | ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name)) | |
576 | } | |
577 | Region::LateBoundAnon(_, _, anon_idx) => { | |
578 | ty::BoundVariableKind::Region(ty::BrAnon(*anon_idx)) | |
579 | } | |
580 | _ => bug!("{:?} is not a late region", region), | |
581 | } | |
582 | } | |
583 | ||
17df50a5 XL |
584 | #[tracing::instrument(level = "debug")] |
585 | fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath { | |
586 | let mut available_lifetimes = vec![]; | |
587 | loop { | |
588 | match scope { | |
589 | Scope::Binder { lifetimes, s, .. } => { | |
590 | available_lifetimes.extend(lifetimes.keys().filter_map(|p| match p { | |
591 | hir::ParamName::Plain(ident) => Some(ident.name.to_string()), | |
592 | _ => None, | |
593 | })); | |
594 | scope = s; | |
595 | } | |
596 | Scope::Body { s, .. } => { | |
597 | scope = s; | |
598 | } | |
599 | Scope::Elision { elide, s } => { | |
600 | if let Elide::Exact(_) = elide { | |
601 | return LifetimeScopeForPath::Elided; | |
602 | } else { | |
603 | scope = s; | |
604 | } | |
605 | } | |
606 | Scope::ObjectLifetimeDefault { s, .. } => { | |
607 | scope = s; | |
608 | } | |
609 | Scope::Root => { | |
610 | return LifetimeScopeForPath::NonElided(available_lifetimes); | |
611 | } | |
612 | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { | |
613 | scope = s; | |
614 | } | |
615 | } | |
616 | } | |
617 | } | |
618 | ||
cdc7bbd5 XL |
619 | impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { |
620 | /// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref. | |
621 | fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderScopeType) { | |
622 | let mut scope = self.scope; | |
623 | let mut supertrait_lifetimes = vec![]; | |
624 | loop { | |
625 | match scope { | |
626 | Scope::Body { .. } | Scope::Root => { | |
627 | break (vec![], BinderScopeType::Normal); | |
628 | } | |
629 | ||
630 | Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { | |
631 | scope = s; | |
632 | } | |
633 | ||
634 | Scope::Supertrait { s, lifetimes } => { | |
635 | supertrait_lifetimes = lifetimes.clone(); | |
636 | scope = s; | |
637 | } | |
638 | ||
639 | Scope::TraitRefBoundary { .. } => { | |
640 | // We should only see super trait lifetimes if there is a `Binder` above | |
641 | assert!(supertrait_lifetimes.is_empty()); | |
642 | break (vec![], BinderScopeType::Normal); | |
643 | } | |
644 | ||
645 | Scope::Binder { hir_id, .. } => { | |
646 | // Nested poly trait refs have the binders concatenated | |
647 | let mut full_binders = | |
648 | self.map.late_bound_vars.entry(*hir_id).or_default().clone(); | |
649 | full_binders.extend(supertrait_lifetimes.into_iter()); | |
650 | break (full_binders, BinderScopeType::Concatenating); | |
651 | } | |
652 | } | |
653 | } | |
654 | } | |
655 | } | |
dfeec247 XL |
656 | impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { |
657 | type Map = Map<'tcx>; | |
658 | ||
ba9703b0 XL |
659 | fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
660 | NestedVisitorMap::All(self.tcx.hir()) | |
dfeec247 XL |
661 | } |
662 | ||
663 | // We want to nest trait/impl items in their parent, but nothing else. | |
664 | fn visit_nested_item(&mut self, _: hir::ItemId) {} | |
665 | ||
cdc7bbd5 XL |
666 | fn visit_trait_item_ref(&mut self, ii: &'tcx hir::TraitItemRef) { |
667 | if !self.trait_definition_only { | |
668 | intravisit::walk_trait_item_ref(self, ii) | |
669 | } | |
670 | } | |
671 | ||
dfeec247 XL |
672 | fn visit_nested_body(&mut self, body: hir::BodyId) { |
673 | // Each body has their own set of labels, save labels. | |
674 | let saved = take(&mut self.labels_in_fn); | |
675 | let body = self.tcx.hir().body(body); | |
676 | extract_labels(self, body); | |
677 | self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| { | |
678 | this.visit_body(body); | |
679 | }); | |
f9f354fc | 680 | self.labels_in_fn = saved; |
dfeec247 XL |
681 | } |
682 | ||
cdc7bbd5 XL |
683 | fn visit_fn( |
684 | &mut self, | |
685 | fk: intravisit::FnKind<'tcx>, | |
686 | fd: &'tcx hir::FnDecl<'tcx>, | |
687 | b: hir::BodyId, | |
688 | s: rustc_span::Span, | |
689 | hir_id: hir::HirId, | |
690 | ) { | |
691 | let name = match fk { | |
692 | intravisit::FnKind::ItemFn(id, _, _, _) => id.as_str(), | |
693 | intravisit::FnKind::Method(id, _, _) => id.as_str(), | |
694 | intravisit::FnKind::Closure => Symbol::intern("closure").as_str(), | |
695 | }; | |
696 | let name: &str = &name; | |
697 | let span = span!(Level::DEBUG, "visit_fn", name); | |
698 | let _enter = span.enter(); | |
699 | match fk { | |
700 | // Any `Binders` are handled elsewhere | |
701 | intravisit::FnKind::ItemFn(..) | intravisit::FnKind::Method(..) => { | |
702 | intravisit::walk_fn(self, fk, fd, b, s, hir_id) | |
703 | } | |
704 | intravisit::FnKind::Closure => { | |
705 | self.map.late_bound_vars.insert(hir_id, vec![]); | |
706 | let scope = Scope::Binder { | |
707 | hir_id, | |
17df50a5 | 708 | lifetimes: FxIndexMap::default(), |
cdc7bbd5 XL |
709 | next_early_index: self.next_early_index(), |
710 | s: self.scope, | |
711 | track_lifetime_uses: true, | |
712 | opaque_type_parent: false, | |
713 | scope_type: BinderScopeType::Normal, | |
714 | }; | |
715 | self.with(scope, move |_old_scope, this| { | |
716 | intravisit::walk_fn(this, fk, fd, b, s, hir_id) | |
717 | }); | |
718 | } | |
719 | } | |
720 | } | |
721 | ||
dfeec247 | 722 | fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { |
cdc7bbd5 XL |
723 | match &item.kind { |
724 | hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => { | |
725 | if let Some(of_trait) = of_trait { | |
726 | self.map.late_bound_vars.insert(of_trait.hir_ref_id, Vec::default()); | |
727 | } | |
728 | } | |
729 | _ => {} | |
730 | } | |
dfeec247 XL |
731 | match item.kind { |
732 | hir::ItemKind::Fn(ref sig, ref generics, _) => { | |
74b04a01 | 733 | self.missing_named_lifetime_spots.push(generics.into()); |
cdc7bbd5 | 734 | self.visit_early_late(None, item.hir_id(), &sig.decl, generics, |this| { |
dfeec247 XL |
735 | intravisit::walk_item(this, item); |
736 | }); | |
737 | self.missing_named_lifetime_spots.pop(); | |
738 | } | |
739 | ||
740 | hir::ItemKind::ExternCrate(_) | |
741 | | hir::ItemKind::Use(..) | |
94222f64 | 742 | | hir::ItemKind::Macro(..) |
dfeec247 | 743 | | hir::ItemKind::Mod(..) |
fc512014 | 744 | | hir::ItemKind::ForeignMod { .. } |
dfeec247 XL |
745 | | hir::ItemKind::GlobalAsm(..) => { |
746 | // These sorts of items have no lifetime parameters at all. | |
747 | intravisit::walk_item(self, item); | |
748 | } | |
749 | hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { | |
750 | // No lifetime parameters, but implied 'static. | |
751 | let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE }; | |
752 | self.with(scope, |_, this| intravisit::walk_item(this, item)); | |
753 | } | |
f035d41b XL |
754 | hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => { |
755 | // Opaque types are visited when we visit the | |
756 | // `TyKind::OpaqueDef`, so that they have the lifetimes from | |
757 | // their parent opaque_ty in scope. | |
cdc7bbd5 XL |
758 | // |
759 | // The core idea here is that since OpaqueTys are generated with the impl Trait as | |
760 | // their owner, we can keep going until we find the Item that owns that. We then | |
761 | // conservatively add all resolved lifetimes. Otherwise we run into problems in | |
762 | // cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`. | |
763 | for (_hir_id, node) in | |
764 | self.tcx.hir().parent_iter(self.tcx.hir().local_def_id_to_hir_id(item.def_id)) | |
765 | { | |
766 | match node { | |
767 | hir::Node::Item(parent_item) => { | |
768 | let resolved_lifetimes: &ResolveLifetimes = | |
769 | self.tcx.resolve_lifetimes(item_for(self.tcx, parent_item.def_id)); | |
770 | // We need to add *all* deps, since opaque tys may want them from *us* | |
771 | for (&owner, defs) in resolved_lifetimes.defs.iter() { | |
772 | defs.iter().for_each(|(&local_id, region)| { | |
17df50a5 | 773 | self.map.defs.insert(hir::HirId { owner, local_id }, *region); |
cdc7bbd5 XL |
774 | }); |
775 | } | |
776 | for (&owner, late_bound) in resolved_lifetimes.late_bound.iter() { | |
777 | late_bound.iter().for_each(|&local_id| { | |
778 | self.map.late_bound.insert(hir::HirId { owner, local_id }); | |
779 | }); | |
780 | } | |
781 | for (&owner, late_bound_vars) in | |
782 | resolved_lifetimes.late_bound_vars.iter() | |
783 | { | |
784 | late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| { | |
785 | self.map.late_bound_vars.insert( | |
786 | hir::HirId { owner, local_id }, | |
787 | late_bound_vars.clone(), | |
788 | ); | |
789 | }); | |
790 | } | |
791 | break; | |
792 | } | |
793 | hir::Node::Crate(_) => bug!("No Item about an OpaqueTy"), | |
794 | _ => {} | |
795 | } | |
796 | } | |
dfeec247 XL |
797 | } |
798 | hir::ItemKind::TyAlias(_, ref generics) | |
dfeec247 XL |
799 | | hir::ItemKind::Enum(_, ref generics) |
800 | | hir::ItemKind::Struct(_, ref generics) | |
801 | | hir::ItemKind::Union(_, ref generics) | |
802 | | hir::ItemKind::Trait(_, _, ref generics, ..) | |
803 | | hir::ItemKind::TraitAlias(ref generics, ..) | |
5869c6ff | 804 | | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => { |
74b04a01 | 805 | self.missing_named_lifetime_spots.push(generics.into()); |
dfeec247 XL |
806 | |
807 | // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name". | |
5869c6ff | 808 | // This is not true for other kinds of items. |
29967ef6 | 809 | let track_lifetime_uses = matches!(item.kind, hir::ItemKind::Impl { .. }); |
dfeec247 XL |
810 | // These kinds of items have only early-bound lifetime parameters. |
811 | let mut index = if sub_items_have_self_param(&item.kind) { | |
812 | 1 // Self comes before lifetimes | |
813 | } else { | |
814 | 0 | |
815 | }; | |
816 | let mut non_lifetime_count = 0; | |
817 | let lifetimes = generics | |
818 | .params | |
819 | .iter() | |
820 | .filter_map(|param| match param.kind { | |
821 | GenericParamKind::Lifetime { .. } => { | |
822 | Some(Region::early(&self.tcx.hir(), &mut index, param)) | |
823 | } | |
824 | GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { | |
825 | non_lifetime_count += 1; | |
826 | None | |
827 | } | |
828 | }) | |
829 | .collect(); | |
cdc7bbd5 | 830 | self.map.late_bound_vars.insert(item.hir_id(), vec![]); |
dfeec247 | 831 | let scope = Scope::Binder { |
cdc7bbd5 | 832 | hir_id: item.hir_id(), |
dfeec247 XL |
833 | lifetimes, |
834 | next_early_index: index + non_lifetime_count, | |
835 | opaque_type_parent: true, | |
836 | track_lifetime_uses, | |
cdc7bbd5 | 837 | scope_type: BinderScopeType::Normal, |
dfeec247 XL |
838 | s: ROOT_SCOPE, |
839 | }; | |
840 | self.with(scope, |old_scope, this| { | |
841 | this.check_lifetime_params(old_scope, &generics.params); | |
cdc7bbd5 XL |
842 | let scope = Scope::TraitRefBoundary { s: this.scope }; |
843 | this.with(scope, |_, this| { | |
844 | intravisit::walk_item(this, item); | |
845 | }); | |
dfeec247 XL |
846 | }); |
847 | self.missing_named_lifetime_spots.pop(); | |
848 | } | |
849 | } | |
850 | } | |
851 | ||
852 | fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { | |
853 | match item.kind { | |
854 | hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { | |
cdc7bbd5 | 855 | self.visit_early_late(None, item.hir_id(), decl, generics, |this| { |
dfeec247 XL |
856 | intravisit::walk_foreign_item(this, item); |
857 | }) | |
858 | } | |
859 | hir::ForeignItemKind::Static(..) => { | |
860 | intravisit::walk_foreign_item(self, item); | |
861 | } | |
862 | hir::ForeignItemKind::Type => { | |
863 | intravisit::walk_foreign_item(self, item); | |
864 | } | |
865 | } | |
866 | } | |
867 | ||
cdc7bbd5 | 868 | #[tracing::instrument(level = "debug", skip(self))] |
dfeec247 | 869 | fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { |
dfeec247 XL |
870 | match ty.kind { |
871 | hir::TyKind::BareFn(ref c) => { | |
872 | let next_early_index = self.next_early_index(); | |
873 | let was_in_fn_syntax = self.is_in_fn_syntax; | |
874 | self.is_in_fn_syntax = true; | |
f9f354fc XL |
875 | let lifetime_span: Option<Span> = |
876 | c.generic_params.iter().rev().find_map(|param| match param.kind { | |
74b04a01 XL |
877 | GenericParamKind::Lifetime { .. } => Some(param.span), |
878 | _ => None, | |
f9f354fc | 879 | }); |
74b04a01 XL |
880 | let (span, span_type) = if let Some(span) = lifetime_span { |
881 | (span.shrink_to_hi(), ForLifetimeSpanType::TypeTail) | |
882 | } else { | |
883 | (ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty) | |
884 | }; | |
885 | self.missing_named_lifetime_spots | |
886 | .push(MissingLifetimeSpot::HigherRanked { span, span_type }); | |
17df50a5 | 887 | let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = c |
cdc7bbd5 XL |
888 | .generic_params |
889 | .iter() | |
890 | .filter_map(|param| match param.kind { | |
891 | GenericParamKind::Lifetime { .. } => Some(param), | |
892 | _ => None, | |
893 | }) | |
894 | .enumerate() | |
895 | .map(|(late_bound_idx, param)| { | |
896 | let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param); | |
897 | let r = late_region_as_bound_region(self.tcx, &pair.1); | |
898 | (pair, r) | |
899 | }) | |
900 | .unzip(); | |
901 | self.map.late_bound_vars.insert(ty.hir_id, binders); | |
dfeec247 | 902 | let scope = Scope::Binder { |
cdc7bbd5 XL |
903 | hir_id: ty.hir_id, |
904 | lifetimes, | |
dfeec247 XL |
905 | s: self.scope, |
906 | next_early_index, | |
907 | track_lifetime_uses: true, | |
908 | opaque_type_parent: false, | |
cdc7bbd5 | 909 | scope_type: BinderScopeType::Normal, |
dfeec247 XL |
910 | }; |
911 | self.with(scope, |old_scope, this| { | |
912 | // a bare fn has no bounds, so everything | |
913 | // contained within is scoped within its binder. | |
914 | this.check_lifetime_params(old_scope, &c.generic_params); | |
915 | intravisit::walk_ty(this, ty); | |
916 | }); | |
74b04a01 | 917 | self.missing_named_lifetime_spots.pop(); |
dfeec247 XL |
918 | self.is_in_fn_syntax = was_in_fn_syntax; |
919 | } | |
6a06907d | 920 | hir::TyKind::TraitObject(bounds, ref lifetime, _) => { |
cdc7bbd5 XL |
921 | debug!(?bounds, ?lifetime, "TraitObject"); |
922 | let scope = Scope::TraitRefBoundary { s: self.scope }; | |
923 | self.with(scope, |_, this| { | |
924 | for bound in bounds { | |
925 | this.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); | |
926 | } | |
927 | }); | |
dfeec247 XL |
928 | match lifetime.name { |
929 | LifetimeName::Implicit => { | |
930 | // For types like `dyn Foo`, we should | |
931 | // generate a special form of elided. | |
74b04a01 | 932 | span_bug!(ty.span, "object-lifetime-default expected, not implicit",); |
dfeec247 XL |
933 | } |
934 | LifetimeName::ImplicitObjectLifetimeDefault => { | |
935 | // If the user does not write *anything*, we | |
936 | // use the object lifetime defaulting | |
937 | // rules. So e.g., `Box<dyn Debug>` becomes | |
938 | // `Box<dyn Debug + 'static>`. | |
939 | self.resolve_object_lifetime_default(lifetime) | |
940 | } | |
941 | LifetimeName::Underscore => { | |
942 | // If the user writes `'_`, we use the *ordinary* elision | |
943 | // rules. So the `'_` in e.g., `Box<dyn Debug + '_>` will be | |
944 | // resolved the same as the `'_` in `&'_ Foo`. | |
945 | // | |
946 | // cc #48468 | |
cdc7bbd5 | 947 | self.resolve_elided_lifetimes(&[lifetime]) |
dfeec247 XL |
948 | } |
949 | LifetimeName::Param(_) | LifetimeName::Static => { | |
950 | // If the user wrote an explicit name, use that. | |
951 | self.visit_lifetime(lifetime); | |
952 | } | |
953 | LifetimeName::Error => {} | |
954 | } | |
955 | } | |
956 | hir::TyKind::Rptr(ref lifetime_ref, ref mt) => { | |
957 | self.visit_lifetime(lifetime_ref); | |
958 | let scope = Scope::ObjectLifetimeDefault { | |
959 | lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(), | |
960 | s: self.scope, | |
961 | }; | |
962 | self.with(scope, |_, this| this.visit_ty(&mt.ty)); | |
963 | } | |
f035d41b | 964 | hir::TyKind::OpaqueDef(item_id, lifetimes) => { |
dfeec247 XL |
965 | // Resolve the lifetimes in the bounds to the lifetime defs in the generics. |
966 | // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to | |
967 | // `type MyAnonTy<'b> = impl MyTrait<'b>;` | |
968 | // ^ ^ this gets resolved in the scope of | |
969 | // the opaque_ty generics | |
6a06907d | 970 | let opaque_ty = self.tcx.hir().item(item_id); |
f035d41b | 971 | let (generics, bounds) = match opaque_ty.kind { |
dfeec247 XL |
972 | // Named opaque `impl Trait` types are reached via `TyKind::Path`. |
973 | // This arm is for `impl Trait` in the types of statics, constants and locals. | |
974 | hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => { | |
975 | intravisit::walk_ty(self, ty); | |
f035d41b XL |
976 | |
977 | // Elided lifetimes are not allowed in non-return | |
978 | // position impl Trait | |
cdc7bbd5 | 979 | let scope = Scope::TraitRefBoundary { s: self.scope }; |
f035d41b | 980 | self.with(scope, |_, this| { |
cdc7bbd5 XL |
981 | let scope = Scope::Elision { elide: Elide::Forbid, s: this.scope }; |
982 | this.with(scope, |_, this| { | |
983 | intravisit::walk_item(this, opaque_ty); | |
984 | }) | |
f035d41b XL |
985 | }); |
986 | ||
dfeec247 XL |
987 | return; |
988 | } | |
989 | // RPIT (return position impl trait) | |
f035d41b XL |
990 | hir::ItemKind::OpaqueTy(hir::OpaqueTy { |
991 | impl_trait_fn: Some(_), | |
992 | ref generics, | |
993 | bounds, | |
994 | .. | |
995 | }) => (generics, bounds), | |
dfeec247 XL |
996 | ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), |
997 | }; | |
998 | ||
999 | // Resolve the lifetimes that are applied to the opaque type. | |
1000 | // These are resolved in the current scope. | |
1001 | // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to | |
1002 | // `fn foo<'a>() -> MyAnonTy<'a> { ... }` | |
1003 | // ^ ^this gets resolved in the current scope | |
1004 | for lifetime in lifetimes { | |
1005 | if let hir::GenericArg::Lifetime(lifetime) = lifetime { | |
1006 | self.visit_lifetime(lifetime); | |
1007 | ||
1008 | // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>` | |
1009 | // and ban them. Type variables instantiated inside binders aren't | |
1010 | // well-supported at the moment, so this doesn't work. | |
1011 | // In the future, this should be fixed and this error should be removed. | |
1012 | let def = self.map.defs.get(&lifetime.hir_id).cloned(); | |
cdc7bbd5 | 1013 | if let Some(Region::LateBound(_, _, def_id, _)) = def { |
f9f354fc | 1014 | if let Some(def_id) = def_id.as_local() { |
3dfed10e | 1015 | let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); |
dfeec247 XL |
1016 | // Ensure that the parent of the def is an item, not HRTB |
1017 | let parent_id = self.tcx.hir().get_parent_node(hir_id); | |
94222f64 XL |
1018 | // FIXME(cjgillot) Can this check be replaced by |
1019 | // `let parent_is_item = parent_id.is_owner();`? | |
1020 | let parent_is_item = | |
1021 | if let Some(parent_def_id) = parent_id.as_owner() { | |
1022 | matches!( | |
1023 | self.tcx.hir().krate().owners.get(parent_def_id), | |
1024 | Some(Some(_)), | |
1025 | ) | |
1026 | } else { | |
1027 | false | |
1028 | }; | |
6a06907d XL |
1029 | |
1030 | if !parent_is_item { | |
cdc7bbd5 XL |
1031 | if !self.trait_definition_only { |
1032 | struct_span_err!( | |
1033 | self.tcx.sess, | |
1034 | lifetime.span, | |
1035 | E0657, | |
1036 | "`impl Trait` can only capture lifetimes \ | |
1037 | bound at the fn or impl level" | |
1038 | ) | |
1039 | .emit(); | |
1040 | } | |
dfeec247 XL |
1041 | self.uninsert_lifetime_on_error(lifetime, def.unwrap()); |
1042 | } | |
1043 | } | |
1044 | } | |
1045 | } | |
1046 | } | |
1047 | ||
1048 | // We want to start our early-bound indices at the end of the parent scope, | |
1049 | // not including any parent `impl Trait`s. | |
1050 | let mut index = self.next_early_index_for_opaque_type(); | |
cdc7bbd5 | 1051 | debug!(?index); |
dfeec247 XL |
1052 | |
1053 | let mut elision = None; | |
17df50a5 | 1054 | let mut lifetimes = FxIndexMap::default(); |
dfeec247 XL |
1055 | let mut non_lifetime_count = 0; |
1056 | for param in generics.params { | |
1057 | match param.kind { | |
1058 | GenericParamKind::Lifetime { .. } => { | |
1059 | let (name, reg) = Region::early(&self.tcx.hir(), &mut index, ¶m); | |
1060 | let def_id = if let Region::EarlyBound(_, def_id, _) = reg { | |
1061 | def_id | |
1062 | } else { | |
1063 | bug!(); | |
1064 | }; | |
5869c6ff XL |
1065 | // We cannot predict what lifetimes are unused in opaque type. |
1066 | self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); | |
1067 | if let hir::ParamName::Plain(Ident { | |
1068 | name: kw::UnderscoreLifetime, | |
1069 | .. | |
1070 | }) = name | |
1071 | { | |
1072 | // Pick the elided lifetime "definition" if one exists | |
1073 | // and use it to make an elision scope. | |
1074 | elision = Some(reg); | |
dfeec247 | 1075 | } else { |
dfeec247 XL |
1076 | lifetimes.insert(name, reg); |
1077 | } | |
1078 | } | |
1079 | GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { | |
1080 | non_lifetime_count += 1; | |
1081 | } | |
1082 | } | |
1083 | } | |
1084 | let next_early_index = index + non_lifetime_count; | |
cdc7bbd5 | 1085 | self.map.late_bound_vars.insert(ty.hir_id, vec![]); |
dfeec247 XL |
1086 | |
1087 | if let Some(elision_region) = elision { | |
1088 | let scope = | |
1089 | Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope }; | |
1090 | self.with(scope, |_old_scope, this| { | |
1091 | let scope = Scope::Binder { | |
cdc7bbd5 | 1092 | hir_id: ty.hir_id, |
dfeec247 XL |
1093 | lifetimes, |
1094 | next_early_index, | |
1095 | s: this.scope, | |
1096 | track_lifetime_uses: true, | |
1097 | opaque_type_parent: false, | |
cdc7bbd5 | 1098 | scope_type: BinderScopeType::Normal, |
dfeec247 XL |
1099 | }; |
1100 | this.with(scope, |_old_scope, this| { | |
1101 | this.visit_generics(generics); | |
cdc7bbd5 XL |
1102 | let scope = Scope::TraitRefBoundary { s: this.scope }; |
1103 | this.with(scope, |_, this| { | |
1104 | for bound in bounds { | |
1105 | this.visit_param_bound(bound); | |
1106 | } | |
1107 | }) | |
dfeec247 XL |
1108 | }); |
1109 | }); | |
1110 | } else { | |
1111 | let scope = Scope::Binder { | |
cdc7bbd5 | 1112 | hir_id: ty.hir_id, |
dfeec247 XL |
1113 | lifetimes, |
1114 | next_early_index, | |
1115 | s: self.scope, | |
1116 | track_lifetime_uses: true, | |
1117 | opaque_type_parent: false, | |
cdc7bbd5 | 1118 | scope_type: BinderScopeType::Normal, |
dfeec247 XL |
1119 | }; |
1120 | self.with(scope, |_old_scope, this| { | |
cdc7bbd5 XL |
1121 | let scope = Scope::TraitRefBoundary { s: this.scope }; |
1122 | this.with(scope, |_, this| { | |
1123 | this.visit_generics(generics); | |
1124 | for bound in bounds { | |
1125 | this.visit_param_bound(bound); | |
1126 | } | |
1127 | }) | |
dfeec247 XL |
1128 | }); |
1129 | } | |
1130 | } | |
1131 | _ => intravisit::walk_ty(self, ty), | |
1132 | } | |
1133 | } | |
1134 | ||
1135 | fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { | |
1136 | use self::hir::TraitItemKind::*; | |
dfeec247 | 1137 | match trait_item.kind { |
ba9703b0 | 1138 | Fn(ref sig, _) => { |
3dfed10e | 1139 | self.missing_named_lifetime_spots.push((&trait_item.generics).into()); |
dfeec247 XL |
1140 | let tcx = self.tcx; |
1141 | self.visit_early_late( | |
6a06907d | 1142 | Some(tcx.hir().get_parent_item(trait_item.hir_id())), |
cdc7bbd5 | 1143 | trait_item.hir_id(), |
dfeec247 XL |
1144 | &sig.decl, |
1145 | &trait_item.generics, | |
1146 | |this| intravisit::walk_trait_item(this, trait_item), | |
1147 | ); | |
3dfed10e | 1148 | self.missing_named_lifetime_spots.pop(); |
dfeec247 XL |
1149 | } |
1150 | Type(bounds, ref ty) => { | |
3dfed10e | 1151 | self.missing_named_lifetime_spots.push((&trait_item.generics).into()); |
dfeec247 XL |
1152 | let generics = &trait_item.generics; |
1153 | let mut index = self.next_early_index(); | |
1154 | debug!("visit_ty: index = {}", index); | |
1155 | let mut non_lifetime_count = 0; | |
1156 | let lifetimes = generics | |
1157 | .params | |
1158 | .iter() | |
1159 | .filter_map(|param| match param.kind { | |
1160 | GenericParamKind::Lifetime { .. } => { | |
1161 | Some(Region::early(&self.tcx.hir(), &mut index, param)) | |
1162 | } | |
1163 | GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { | |
1164 | non_lifetime_count += 1; | |
1165 | None | |
1166 | } | |
1167 | }) | |
1168 | .collect(); | |
cdc7bbd5 | 1169 | self.map.late_bound_vars.insert(trait_item.hir_id(), vec![]); |
dfeec247 | 1170 | let scope = Scope::Binder { |
cdc7bbd5 | 1171 | hir_id: trait_item.hir_id(), |
dfeec247 XL |
1172 | lifetimes, |
1173 | next_early_index: index + non_lifetime_count, | |
1174 | s: self.scope, | |
1175 | track_lifetime_uses: true, | |
1176 | opaque_type_parent: true, | |
cdc7bbd5 | 1177 | scope_type: BinderScopeType::Normal, |
dfeec247 | 1178 | }; |
74b04a01 XL |
1179 | self.with(scope, |old_scope, this| { |
1180 | this.check_lifetime_params(old_scope, &generics.params); | |
cdc7bbd5 XL |
1181 | let scope = Scope::TraitRefBoundary { s: this.scope }; |
1182 | this.with(scope, |_, this| { | |
1183 | this.visit_generics(generics); | |
1184 | for bound in bounds { | |
1185 | this.visit_param_bound(bound); | |
1186 | } | |
1187 | if let Some(ty) = ty { | |
1188 | this.visit_ty(ty); | |
1189 | } | |
1190 | }) | |
dfeec247 | 1191 | }); |
3dfed10e | 1192 | self.missing_named_lifetime_spots.pop(); |
dfeec247 XL |
1193 | } |
1194 | Const(_, _) => { | |
1195 | // Only methods and types support generics. | |
1196 | assert!(trait_item.generics.params.is_empty()); | |
3dfed10e | 1197 | self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static); |
dfeec247 | 1198 | intravisit::walk_trait_item(self, trait_item); |
3dfed10e | 1199 | self.missing_named_lifetime_spots.pop(); |
dfeec247 XL |
1200 | } |
1201 | } | |
dfeec247 XL |
1202 | } |
1203 | ||
1204 | fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { | |
1205 | use self::hir::ImplItemKind::*; | |
dfeec247 | 1206 | match impl_item.kind { |
ba9703b0 | 1207 | Fn(ref sig, _) => { |
3dfed10e | 1208 | self.missing_named_lifetime_spots.push((&impl_item.generics).into()); |
dfeec247 XL |
1209 | let tcx = self.tcx; |
1210 | self.visit_early_late( | |
6a06907d | 1211 | Some(tcx.hir().get_parent_item(impl_item.hir_id())), |
cdc7bbd5 | 1212 | impl_item.hir_id(), |
dfeec247 XL |
1213 | &sig.decl, |
1214 | &impl_item.generics, | |
1215 | |this| intravisit::walk_impl_item(this, impl_item), | |
3dfed10e XL |
1216 | ); |
1217 | self.missing_named_lifetime_spots.pop(); | |
dfeec247 XL |
1218 | } |
1219 | TyAlias(ref ty) => { | |
1220 | let generics = &impl_item.generics; | |
3dfed10e | 1221 | self.missing_named_lifetime_spots.push(generics.into()); |
dfeec247 XL |
1222 | let mut index = self.next_early_index(); |
1223 | let mut non_lifetime_count = 0; | |
1224 | debug!("visit_ty: index = {}", index); | |
17df50a5 | 1225 | let lifetimes: FxIndexMap<hir::ParamName, Region> = generics |
dfeec247 XL |
1226 | .params |
1227 | .iter() | |
1228 | .filter_map(|param| match param.kind { | |
1229 | GenericParamKind::Lifetime { .. } => { | |
1230 | Some(Region::early(&self.tcx.hir(), &mut index, param)) | |
1231 | } | |
1232 | GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => { | |
1233 | non_lifetime_count += 1; | |
1234 | None | |
1235 | } | |
1236 | }) | |
1237 | .collect(); | |
cdc7bbd5 | 1238 | self.map.late_bound_vars.insert(ty.hir_id, vec![]); |
dfeec247 | 1239 | let scope = Scope::Binder { |
cdc7bbd5 | 1240 | hir_id: ty.hir_id, |
dfeec247 XL |
1241 | lifetimes, |
1242 | next_early_index: index + non_lifetime_count, | |
1243 | s: self.scope, | |
1244 | track_lifetime_uses: true, | |
1245 | opaque_type_parent: true, | |
cdc7bbd5 | 1246 | scope_type: BinderScopeType::Normal, |
dfeec247 | 1247 | }; |
74b04a01 XL |
1248 | self.with(scope, |old_scope, this| { |
1249 | this.check_lifetime_params(old_scope, &generics.params); | |
cdc7bbd5 XL |
1250 | let scope = Scope::TraitRefBoundary { s: this.scope }; |
1251 | this.with(scope, |_, this| { | |
1252 | this.visit_generics(generics); | |
1253 | this.visit_ty(ty); | |
1254 | }) | |
dfeec247 | 1255 | }); |
3dfed10e | 1256 | self.missing_named_lifetime_spots.pop(); |
dfeec247 | 1257 | } |
dfeec247 XL |
1258 | Const(_, _) => { |
1259 | // Only methods and types support generics. | |
1260 | assert!(impl_item.generics.params.is_empty()); | |
3dfed10e | 1261 | self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static); |
dfeec247 | 1262 | intravisit::walk_impl_item(self, impl_item); |
3dfed10e | 1263 | self.missing_named_lifetime_spots.pop(); |
dfeec247 XL |
1264 | } |
1265 | } | |
dfeec247 XL |
1266 | } |
1267 | ||
cdc7bbd5 | 1268 | #[tracing::instrument(level = "debug", skip(self))] |
dfeec247 | 1269 | fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { |
dfeec247 | 1270 | if lifetime_ref.is_elided() { |
cdc7bbd5 | 1271 | self.resolve_elided_lifetimes(&[lifetime_ref]); |
dfeec247 XL |
1272 | return; |
1273 | } | |
1274 | if lifetime_ref.is_static() { | |
1275 | self.insert_lifetime(lifetime_ref, Region::Static); | |
1276 | return; | |
1277 | } | |
3dfed10e XL |
1278 | if self.is_in_const_generic && lifetime_ref.name != LifetimeName::Error { |
1279 | self.emit_non_static_lt_in_const_generic_error(lifetime_ref); | |
1280 | return; | |
1281 | } | |
dfeec247 XL |
1282 | self.resolve_lifetime_ref(lifetime_ref); |
1283 | } | |
1284 | ||
17df50a5 XL |
1285 | fn visit_assoc_type_binding(&mut self, type_binding: &'tcx hir::TypeBinding<'_>) { |
1286 | let scope = self.scope; | |
1287 | if let Some(scope_for_path) = self.map.scope_for_path.as_mut() { | |
1288 | // We add lifetime scope information for `Ident`s in associated type bindings and use | |
1289 | // the `HirId` of the type binding as the key in `LifetimeMap` | |
1290 | let lifetime_scope = get_lifetime_scopes_for_path(scope); | |
1291 | let map = scope_for_path.entry(type_binding.hir_id.owner).or_default(); | |
1292 | map.insert(type_binding.hir_id.local_id, lifetime_scope); | |
1293 | } | |
1294 | hir::intravisit::walk_assoc_type_binding(self, type_binding); | |
1295 | } | |
1296 | ||
dfeec247 XL |
1297 | fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) { |
1298 | for (i, segment) in path.segments.iter().enumerate() { | |
1299 | let depth = path.segments.len() - i - 1; | |
1300 | if let Some(ref args) = segment.args { | |
1301 | self.visit_segment_args(path.res, depth, args); | |
1302 | } | |
17df50a5 XL |
1303 | |
1304 | let scope = self.scope; | |
1305 | if let Some(scope_for_path) = self.map.scope_for_path.as_mut() { | |
1306 | // Add lifetime scope information to path segment. Note we cannot call `visit_path_segment` | |
1307 | // here because that call would yield to resolution problems due to `walk_path_segment` | |
1308 | // being called, which processes the path segments generic args, which we have already | |
1309 | // processed using `visit_segment_args`. | |
1310 | let lifetime_scope = get_lifetime_scopes_for_path(scope); | |
1311 | if let Some(hir_id) = segment.hir_id { | |
1312 | let map = scope_for_path.entry(hir_id.owner).or_default(); | |
1313 | map.insert(hir_id.local_id, lifetime_scope); | |
1314 | } | |
1315 | } | |
1316 | } | |
1317 | } | |
1318 | ||
1319 | fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx hir::PathSegment<'tcx>) { | |
1320 | let scope = self.scope; | |
1321 | if let Some(scope_for_path) = self.map.scope_for_path.as_mut() { | |
1322 | let lifetime_scope = get_lifetime_scopes_for_path(scope); | |
1323 | if let Some(hir_id) = path_segment.hir_id { | |
1324 | let map = scope_for_path.entry(hir_id.owner).or_default(); | |
1325 | map.insert(hir_id.local_id, lifetime_scope); | |
1326 | } | |
dfeec247 | 1327 | } |
17df50a5 XL |
1328 | |
1329 | intravisit::walk_path_segment(self, path_span, path_segment); | |
dfeec247 XL |
1330 | } |
1331 | ||
1332 | fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) { | |
1333 | let output = match fd.output { | |
74b04a01 XL |
1334 | hir::FnRetTy::DefaultReturn(_) => None, |
1335 | hir::FnRetTy::Return(ref ty) => Some(&**ty), | |
dfeec247 XL |
1336 | }; |
1337 | self.visit_fn_like_elision(&fd.inputs, output); | |
1338 | } | |
1339 | ||
1340 | fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { | |
cdc7bbd5 XL |
1341 | if !self.trait_definition_only { |
1342 | check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params); | |
1343 | } | |
1344 | let scope = Scope::TraitRefBoundary { s: self.scope }; | |
1345 | self.with(scope, |_, this| { | |
1346 | for param in generics.params { | |
1347 | match param.kind { | |
1348 | GenericParamKind::Lifetime { .. } => {} | |
1349 | GenericParamKind::Type { ref default, .. } => { | |
1350 | walk_list!(this, visit_param_bound, param.bounds); | |
1351 | if let Some(ref ty) = default { | |
1352 | this.visit_ty(&ty); | |
1353 | } | |
1354 | } | |
1355 | GenericParamKind::Const { ref ty, .. } => { | |
1356 | let was_in_const_generic = this.is_in_const_generic; | |
1357 | this.is_in_const_generic = true; | |
1358 | walk_list!(this, visit_param_bound, param.bounds); | |
1359 | this.visit_ty(&ty); | |
1360 | this.is_in_const_generic = was_in_const_generic; | |
dfeec247 XL |
1361 | } |
1362 | } | |
cdc7bbd5 XL |
1363 | } |
1364 | for predicate in generics.where_clause.predicates { | |
1365 | match predicate { | |
1366 | &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { | |
1367 | ref bounded_ty, | |
1368 | bounds, | |
1369 | ref bound_generic_params, | |
1370 | .. | |
1371 | }) => { | |
17df50a5 | 1372 | let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = |
cdc7bbd5 XL |
1373 | bound_generic_params |
1374 | .iter() | |
1375 | .filter_map(|param| match param.kind { | |
1376 | GenericParamKind::Lifetime { .. } => Some(param), | |
1377 | _ => None, | |
1378 | }) | |
1379 | .enumerate() | |
1380 | .map(|(late_bound_idx, param)| { | |
1381 | let pair = | |
1382 | Region::late(late_bound_idx as u32, &this.tcx.hir(), param); | |
1383 | let r = late_region_as_bound_region(this.tcx, &pair.1); | |
1384 | (pair, r) | |
1385 | }) | |
1386 | .unzip(); | |
1387 | this.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone()); | |
1388 | let next_early_index = this.next_early_index(); | |
1389 | // Even if there are no lifetimes defined here, we still wrap it in a binder | |
1390 | // scope. If there happens to be a nested poly trait ref (an error), that | |
1391 | // will be `Concatenating` anyways, so we don't have to worry about the depth | |
1392 | // being wrong. | |
dfeec247 | 1393 | let scope = Scope::Binder { |
cdc7bbd5 | 1394 | hir_id: bounded_ty.hir_id, |
dfeec247 | 1395 | lifetimes, |
cdc7bbd5 | 1396 | s: this.scope, |
dfeec247 XL |
1397 | next_early_index, |
1398 | track_lifetime_uses: true, | |
1399 | opaque_type_parent: false, | |
cdc7bbd5 | 1400 | scope_type: BinderScopeType::Normal, |
dfeec247 | 1401 | }; |
cdc7bbd5 | 1402 | this.with(scope, |old_scope, this| { |
dfeec247 XL |
1403 | this.check_lifetime_params(old_scope, &bound_generic_params); |
1404 | this.visit_ty(&bounded_ty); | |
1405 | walk_list!(this, visit_param_bound, bounds); | |
cdc7bbd5 XL |
1406 | }) |
1407 | } | |
1408 | &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { | |
1409 | ref lifetime, | |
1410 | bounds, | |
1411 | .. | |
1412 | }) => { | |
1413 | this.visit_lifetime(lifetime); | |
1414 | walk_list!(this, visit_param_bound, bounds); | |
1415 | } | |
1416 | &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { | |
1417 | ref lhs_ty, | |
1418 | ref rhs_ty, | |
1419 | .. | |
1420 | }) => { | |
1421 | this.visit_ty(lhs_ty); | |
1422 | this.visit_ty(rhs_ty); | |
dfeec247 | 1423 | } |
dfeec247 XL |
1424 | } |
1425 | } | |
cdc7bbd5 | 1426 | }) |
dfeec247 XL |
1427 | } |
1428 | ||
3dfed10e XL |
1429 | fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) { |
1430 | match bound { | |
cdc7bbd5 XL |
1431 | hir::GenericBound::LangItemTrait(_, _, hir_id, _) => { |
1432 | // FIXME(jackh726): This is pretty weird. `LangItemTrait` doesn't go | |
1433 | // through the regular poly trait ref code, so we don't get another | |
1434 | // chance to introduce a binder. For now, I'm keeping the existing logic | |
1435 | // of "if there isn't a Binder scope above us, add one", but I | |
1436 | // imagine there's a better way to go about this. | |
1437 | let (binders, scope_type) = self.poly_trait_ref_binder_info(); | |
1438 | ||
1439 | self.map.late_bound_vars.insert(*hir_id, binders); | |
3dfed10e | 1440 | let scope = Scope::Binder { |
cdc7bbd5 | 1441 | hir_id: *hir_id, |
17df50a5 | 1442 | lifetimes: FxIndexMap::default(), |
3dfed10e XL |
1443 | s: self.scope, |
1444 | next_early_index: self.next_early_index(), | |
1445 | track_lifetime_uses: true, | |
1446 | opaque_type_parent: false, | |
cdc7bbd5 | 1447 | scope_type, |
3dfed10e XL |
1448 | }; |
1449 | self.with(scope, |_, this| { | |
1450 | intravisit::walk_param_bound(this, bound); | |
1451 | }); | |
1452 | } | |
1453 | _ => intravisit::walk_param_bound(self, bound), | |
1454 | } | |
1455 | } | |
1456 | ||
dfeec247 XL |
1457 | fn visit_poly_trait_ref( |
1458 | &mut self, | |
1459 | trait_ref: &'tcx hir::PolyTraitRef<'tcx>, | |
1460 | _modifier: hir::TraitBoundModifier, | |
1461 | ) { | |
1462 | debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); | |
1463 | ||
74b04a01 | 1464 | let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); |
f035d41b | 1465 | |
cdc7bbd5 XL |
1466 | let next_early_index = self.next_early_index(); |
1467 | let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); | |
1468 | ||
1469 | let initial_bound_vars = binders.len() as u32; | |
17df50a5 | 1470 | let mut lifetimes: FxIndexMap<hir::ParamName, Region> = FxIndexMap::default(); |
cdc7bbd5 XL |
1471 | let binders_iter = trait_ref |
1472 | .bound_generic_params | |
1473 | .iter() | |
1474 | .filter_map(|param| match param.kind { | |
1475 | GenericParamKind::Lifetime { .. } => Some(param), | |
1476 | _ => None, | |
1477 | }) | |
1478 | .enumerate() | |
1479 | .map(|(late_bound_idx, param)| { | |
1480 | let pair = Region::late( | |
1481 | initial_bound_vars + late_bound_idx as u32, | |
1482 | &self.tcx.hir(), | |
1483 | param, | |
1484 | ); | |
1485 | let r = late_region_as_bound_region(self.tcx, &pair.1); | |
1486 | lifetimes.insert(pair.0, pair.1); | |
1487 | r | |
f035d41b | 1488 | }); |
cdc7bbd5 XL |
1489 | binders.extend(binders_iter); |
1490 | ||
1491 | debug!(?binders); | |
1492 | self.map.late_bound_vars.insert(trait_ref.trait_ref.hir_ref_id, binders); | |
1493 | ||
1494 | // Always introduce a scope here, even if this is in a where clause and | |
1495 | // we introduced the binders around the bounded Ty. In that case, we | |
1496 | // just reuse the concatenation functionality also present in nested trait | |
1497 | // refs. | |
1498 | let scope = Scope::Binder { | |
1499 | hir_id: trait_ref.trait_ref.hir_ref_id, | |
1500 | lifetimes, | |
1501 | s: self.scope, | |
1502 | next_early_index, | |
1503 | track_lifetime_uses: true, | |
1504 | opaque_type_parent: false, | |
1505 | scope_type, | |
1506 | }; | |
1507 | self.with(scope, |old_scope, this| { | |
1508 | this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); | |
1509 | walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); | |
1510 | this.visit_trait_ref(&trait_ref.trait_ref); | |
1511 | }); | |
1512 | ||
74b04a01 XL |
1513 | if should_pop_missing_lt { |
1514 | self.missing_named_lifetime_spots.pop(); | |
dfeec247 XL |
1515 | } |
1516 | } | |
1517 | } | |
1518 | ||
1519 | #[derive(Copy, Clone, PartialEq)] | |
1520 | enum ShadowKind { | |
1521 | Label, | |
1522 | Lifetime, | |
1523 | } | |
1524 | struct Original { | |
1525 | kind: ShadowKind, | |
1526 | span: Span, | |
1527 | } | |
1528 | struct Shadower { | |
1529 | kind: ShadowKind, | |
1530 | span: Span, | |
1531 | } | |
1532 | ||
1533 | fn original_label(span: Span) -> Original { | |
74b04a01 | 1534 | Original { kind: ShadowKind::Label, span } |
dfeec247 XL |
1535 | } |
1536 | fn shadower_label(span: Span) -> Shadower { | |
74b04a01 | 1537 | Shadower { kind: ShadowKind::Label, span } |
dfeec247 XL |
1538 | } |
1539 | fn original_lifetime(span: Span) -> Original { | |
74b04a01 | 1540 | Original { kind: ShadowKind::Lifetime, span } |
dfeec247 XL |
1541 | } |
1542 | fn shadower_lifetime(param: &hir::GenericParam<'_>) -> Shadower { | |
1543 | Shadower { kind: ShadowKind::Lifetime, span: param.span } | |
1544 | } | |
1545 | ||
1546 | impl ShadowKind { | |
1547 | fn desc(&self) -> &'static str { | |
1548 | match *self { | |
1549 | ShadowKind::Label => "label", | |
1550 | ShadowKind::Lifetime => "lifetime", | |
1551 | } | |
1552 | } | |
1553 | } | |
1554 | ||
1555 | fn check_mixed_explicit_and_in_band_defs(tcx: TyCtxt<'_>, params: &[hir::GenericParam<'_>]) { | |
1556 | let lifetime_params: Vec<_> = params | |
1557 | .iter() | |
1558 | .filter_map(|param| match param.kind { | |
1559 | GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)), | |
1560 | _ => None, | |
1561 | }) | |
1562 | .collect(); | |
1563 | let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit); | |
1564 | let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand); | |
1565 | ||
1566 | if let (Some((_, explicit_span)), Some((_, in_band_span))) = (explicit, in_band) { | |
1567 | struct_span_err!( | |
1568 | tcx.sess, | |
1569 | *in_band_span, | |
1570 | E0688, | |
1571 | "cannot mix in-band and explicit lifetime definitions" | |
1572 | ) | |
1573 | .span_label(*in_band_span, "in-band lifetime definition here") | |
1574 | .span_label(*explicit_span, "explicit lifetime definition here") | |
1575 | .emit(); | |
1576 | } | |
1577 | } | |
1578 | ||
f9f354fc | 1579 | fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shadower: Shadower) { |
dfeec247 XL |
1580 | let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) { |
1581 | // lifetime/lifetime shadowing is an error | |
1582 | struct_span_err!( | |
1583 | tcx.sess, | |
1584 | shadower.span, | |
1585 | E0496, | |
1586 | "{} name `{}` shadows a \ | |
1587 | {} name that is already in scope", | |
1588 | shadower.kind.desc(), | |
1589 | name, | |
1590 | orig.kind.desc() | |
1591 | ) | |
1592 | } else { | |
1593 | // shadowing involving a label is only a warning, due to issues with | |
1594 | // labels and lifetimes not being macro-hygienic. | |
1595 | tcx.sess.struct_span_warn( | |
1596 | shadower.span, | |
1597 | &format!( | |
1598 | "{} name `{}` shadows a \ | |
1599 | {} name that is already in scope", | |
1600 | shadower.kind.desc(), | |
1601 | name, | |
1602 | orig.kind.desc() | |
1603 | ), | |
1604 | ) | |
1605 | }; | |
1606 | err.span_label(orig.span, "first declared here"); | |
fc512014 | 1607 | err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name)); |
dfeec247 XL |
1608 | err.emit(); |
1609 | } | |
1610 | ||
1611 | // Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning | |
1612 | // if one of the label shadows a lifetime or another label. | |
1613 | fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) { | |
1614 | struct GatherLabels<'a, 'tcx> { | |
1615 | tcx: TyCtxt<'tcx>, | |
1616 | scope: ScopeRef<'a>, | |
f9f354fc | 1617 | labels_in_fn: &'a mut Vec<Ident>, |
dfeec247 XL |
1618 | } |
1619 | ||
1620 | let mut gather = | |
1621 | GatherLabels { tcx: ctxt.tcx, scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn }; | |
1622 | gather.visit_body(body); | |
1623 | ||
1624 | impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> { | |
ba9703b0 | 1625 | type Map = intravisit::ErasedMap<'v>; |
dfeec247 | 1626 | |
ba9703b0 | 1627 | fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
dfeec247 XL |
1628 | NestedVisitorMap::None |
1629 | } | |
1630 | ||
1631 | fn visit_expr(&mut self, ex: &hir::Expr<'_>) { | |
1632 | if let Some(label) = expression_label(ex) { | |
1633 | for prior_label in &self.labels_in_fn[..] { | |
1634 | // FIXME (#24278): non-hygienic comparison | |
1635 | if label.name == prior_label.name { | |
1636 | signal_shadowing_problem( | |
1637 | self.tcx, | |
1638 | label.name, | |
1639 | original_label(prior_label.span), | |
1640 | shadower_label(label.span), | |
1641 | ); | |
1642 | } | |
1643 | } | |
1644 | ||
1645 | check_if_label_shadows_lifetime(self.tcx, self.scope, label); | |
1646 | ||
1647 | self.labels_in_fn.push(label); | |
1648 | } | |
1649 | intravisit::walk_expr(self, ex) | |
1650 | } | |
1651 | } | |
1652 | ||
f9f354fc | 1653 | fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> { |
c295e0f8 XL |
1654 | match ex.kind { |
1655 | hir::ExprKind::Loop(_, Some(label), ..) => Some(label.ident), | |
1656 | hir::ExprKind::Block(_, Some(label)) => Some(label.ident), | |
1657 | _ => None, | |
1658 | } | |
dfeec247 XL |
1659 | } |
1660 | ||
f9f354fc | 1661 | fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) { |
dfeec247 XL |
1662 | loop { |
1663 | match *scope { | |
1664 | Scope::Body { s, .. } | |
1665 | | Scope::Elision { s, .. } | |
cdc7bbd5 XL |
1666 | | Scope::ObjectLifetimeDefault { s, .. } |
1667 | | Scope::Supertrait { s, .. } | |
1668 | | Scope::TraitRefBoundary { s, .. } => { | |
dfeec247 XL |
1669 | scope = s; |
1670 | } | |
1671 | ||
1672 | Scope::Root => { | |
1673 | return; | |
1674 | } | |
1675 | ||
1676 | Scope::Binder { ref lifetimes, s, .. } => { | |
1677 | // FIXME (#24278): non-hygienic comparison | |
ba9703b0 XL |
1678 | if let Some(def) = |
1679 | lifetimes.get(&hir::ParamName::Plain(label.normalize_to_macros_2_0())) | |
1680 | { | |
3dfed10e XL |
1681 | let hir_id = |
1682 | tcx.hir().local_def_id_to_hir_id(def.id().unwrap().expect_local()); | |
dfeec247 XL |
1683 | |
1684 | signal_shadowing_problem( | |
1685 | tcx, | |
1686 | label.name, | |
1687 | original_lifetime(tcx.hir().span(hir_id)), | |
1688 | shadower_label(label.span), | |
1689 | ); | |
1690 | return; | |
1691 | } | |
1692 | scope = s; | |
1693 | } | |
1694 | } | |
1695 | } | |
1696 | } | |
1697 | } | |
1698 | ||
cdc7bbd5 XL |
1699 | fn compute_object_lifetime_defaults( |
1700 | tcx: TyCtxt<'_>, | |
1701 | item: &hir::Item<'_>, | |
1702 | ) -> Option<Vec<ObjectLifetimeDefault>> { | |
1703 | match item.kind { | |
1704 | hir::ItemKind::Struct(_, ref generics) | |
1705 | | hir::ItemKind::Union(_, ref generics) | |
1706 | | hir::ItemKind::Enum(_, ref generics) | |
1707 | | hir::ItemKind::OpaqueTy(hir::OpaqueTy { ref generics, impl_trait_fn: None, .. }) | |
1708 | | hir::ItemKind::TyAlias(_, ref generics) | |
1709 | | hir::ItemKind::Trait(_, _, ref generics, ..) => { | |
1710 | let result = object_lifetime_defaults_for_item(tcx, generics); | |
1711 | ||
1712 | // Debugging aid. | |
1713 | let attrs = tcx.hir().attrs(item.hir_id()); | |
1714 | if tcx.sess.contains_name(attrs, sym::rustc_object_lifetime_default) { | |
1715 | let object_lifetime_default_reprs: String = result | |
1716 | .iter() | |
1717 | .map(|set| match *set { | |
1718 | Set1::Empty => "BaseDefault".into(), | |
1719 | Set1::One(Region::Static) => "'static".into(), | |
1720 | Set1::One(Region::EarlyBound(mut i, _, _)) => generics | |
1721 | .params | |
1722 | .iter() | |
1723 | .find_map(|param| match param.kind { | |
1724 | GenericParamKind::Lifetime { .. } => { | |
1725 | if i == 0 { | |
1726 | return Some(param.name.ident().to_string().into()); | |
dfeec247 | 1727 | } |
cdc7bbd5 XL |
1728 | i -= 1; |
1729 | None | |
1730 | } | |
1731 | _ => None, | |
1732 | }) | |
1733 | .unwrap(), | |
1734 | Set1::One(_) => bug!(), | |
1735 | Set1::Many => "Ambiguous".into(), | |
1736 | }) | |
1737 | .collect::<Vec<Cow<'static, str>>>() | |
1738 | .join(","); | |
1739 | tcx.sess.span_err(item.span, &object_lifetime_default_reprs); | |
dfeec247 | 1740 | } |
cdc7bbd5 XL |
1741 | |
1742 | Some(result) | |
dfeec247 | 1743 | } |
cdc7bbd5 | 1744 | _ => None, |
dfeec247 | 1745 | } |
dfeec247 XL |
1746 | } |
1747 | ||
1748 | /// Scan the bounds and where-clauses on parameters to extract bounds | |
1749 | /// of the form `T:'a` so as to determine the `ObjectLifetimeDefault` | |
1750 | /// for each type parameter. | |
1751 | fn object_lifetime_defaults_for_item( | |
1752 | tcx: TyCtxt<'_>, | |
1753 | generics: &hir::Generics<'_>, | |
1754 | ) -> Vec<ObjectLifetimeDefault> { | |
1755 | fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::GenericBound<'_>]) { | |
1756 | for bound in bounds { | |
1757 | if let hir::GenericBound::Outlives(ref lifetime) = *bound { | |
ba9703b0 | 1758 | set.insert(lifetime.name.normalize_to_macros_2_0()); |
dfeec247 XL |
1759 | } |
1760 | } | |
1761 | } | |
1762 | ||
1763 | generics | |
1764 | .params | |
1765 | .iter() | |
1766 | .filter_map(|param| match param.kind { | |
1767 | GenericParamKind::Lifetime { .. } => None, | |
1768 | GenericParamKind::Type { .. } => { | |
1769 | let mut set = Set1::Empty; | |
1770 | ||
1771 | add_bounds(&mut set, ¶m.bounds); | |
1772 | ||
1773 | let param_def_id = tcx.hir().local_def_id(param.hir_id); | |
1774 | for predicate in generics.where_clause.predicates { | |
1775 | // Look for `type: ...` where clauses. | |
1776 | let data = match *predicate { | |
1777 | hir::WherePredicate::BoundPredicate(ref data) => data, | |
1778 | _ => continue, | |
1779 | }; | |
1780 | ||
1781 | // Ignore `for<'a> type: ...` as they can change what | |
1782 | // lifetimes mean (although we could "just" handle it). | |
1783 | if !data.bound_generic_params.is_empty() { | |
1784 | continue; | |
1785 | } | |
1786 | ||
1787 | let res = match data.bounded_ty.kind { | |
1788 | hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res, | |
1789 | _ => continue, | |
1790 | }; | |
1791 | ||
f9f354fc | 1792 | if res == Res::Def(DefKind::TyParam, param_def_id.to_def_id()) { |
dfeec247 XL |
1793 | add_bounds(&mut set, &data.bounds); |
1794 | } | |
1795 | } | |
1796 | ||
1797 | Some(match set { | |
1798 | Set1::Empty => Set1::Empty, | |
1799 | Set1::One(name) => { | |
1800 | if name == hir::LifetimeName::Static { | |
1801 | Set1::One(Region::Static) | |
1802 | } else { | |
1803 | generics | |
1804 | .params | |
1805 | .iter() | |
1806 | .filter_map(|param| match param.kind { | |
1807 | GenericParamKind::Lifetime { .. } => Some(( | |
1808 | param.hir_id, | |
1809 | hir::LifetimeName::Param(param.name), | |
1810 | LifetimeDefOrigin::from_param(param), | |
1811 | )), | |
1812 | _ => None, | |
1813 | }) | |
1814 | .enumerate() | |
1815 | .find(|&(_, (_, lt_name, _))| lt_name == name) | |
1816 | .map_or(Set1::Many, |(i, (id, _, origin))| { | |
1817 | let def_id = tcx.hir().local_def_id(id); | |
f9f354fc XL |
1818 | Set1::One(Region::EarlyBound( |
1819 | i as u32, | |
1820 | def_id.to_def_id(), | |
1821 | origin, | |
1822 | )) | |
dfeec247 XL |
1823 | }) |
1824 | } | |
1825 | } | |
1826 | Set1::Many => Set1::Many, | |
1827 | }) | |
1828 | } | |
1829 | GenericParamKind::Const { .. } => { | |
1830 | // Generic consts don't impose any constraints. | |
3dfed10e XL |
1831 | // |
1832 | // We still store a dummy value here to allow generic parameters | |
1833 | // in an arbitrary order. | |
1834 | Some(Set1::Empty) | |
dfeec247 XL |
1835 | } |
1836 | }) | |
1837 | .collect() | |
1838 | } | |
1839 | ||
1840 | impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { | |
dfeec247 XL |
1841 | fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F) |
1842 | where | |
1843 | F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>), | |
1844 | { | |
1845 | let LifetimeContext { tcx, map, lifetime_uses, .. } = self; | |
1846 | let labels_in_fn = take(&mut self.labels_in_fn); | |
1847 | let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); | |
1848 | let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots); | |
1849 | let mut this = LifetimeContext { | |
1850 | tcx: *tcx, | |
74b04a01 | 1851 | map, |
dfeec247 | 1852 | scope: &wrap_scope, |
dfeec247 | 1853 | is_in_fn_syntax: self.is_in_fn_syntax, |
3dfed10e | 1854 | is_in_const_generic: self.is_in_const_generic, |
cdc7bbd5 | 1855 | trait_definition_only: self.trait_definition_only, |
dfeec247 XL |
1856 | labels_in_fn, |
1857 | xcrate_object_lifetime_defaults, | |
1858 | lifetime_uses, | |
1859 | missing_named_lifetime_spots, | |
1860 | }; | |
cdc7bbd5 XL |
1861 | let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); |
1862 | { | |
1863 | let _enter = span.enter(); | |
1864 | f(self.scope, &mut this); | |
1865 | if !self.trait_definition_only { | |
1866 | this.check_uses_for_lifetimes_defined_by_scope(); | |
1867 | } | |
1868 | } | |
dfeec247 XL |
1869 | self.labels_in_fn = this.labels_in_fn; |
1870 | self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; | |
1871 | self.missing_named_lifetime_spots = this.missing_named_lifetime_spots; | |
1872 | } | |
1873 | ||
1874 | /// helper method to determine the span to remove when suggesting the | |
1875 | /// deletion of a lifetime | |
f9f354fc | 1876 | fn lifetime_deletion_span(&self, name: Ident, generics: &hir::Generics<'_>) -> Option<Span> { |
dfeec247 XL |
1877 | generics.params.iter().enumerate().find_map(|(i, param)| { |
1878 | if param.name.ident() == name { | |
5869c6ff XL |
1879 | let in_band = matches!( |
1880 | param.kind, | |
1881 | hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::InBand } | |
1882 | ); | |
dfeec247 XL |
1883 | if in_band { |
1884 | Some(param.span) | |
29967ef6 XL |
1885 | } else if generics.params.len() == 1 { |
1886 | // if sole lifetime, remove the entire `<>` brackets | |
1887 | Some(generics.span) | |
dfeec247 | 1888 | } else { |
29967ef6 XL |
1889 | // if removing within `<>` brackets, we also want to |
1890 | // delete a leading or trailing comma as appropriate | |
1891 | if i >= generics.params.len() - 1 { | |
1892 | Some(generics.params[i - 1].span.shrink_to_hi().to(param.span)) | |
dfeec247 | 1893 | } else { |
29967ef6 | 1894 | Some(param.span.to(generics.params[i + 1].span.shrink_to_lo())) |
dfeec247 XL |
1895 | } |
1896 | } | |
1897 | } else { | |
1898 | None | |
1899 | } | |
1900 | }) | |
1901 | } | |
1902 | ||
1903 | // helper method to issue suggestions from `fn rah<'a>(&'a T)` to `fn rah(&T)` | |
1904 | // or from `fn rah<'a>(T<'a>)` to `fn rah(T<'_>)` | |
1905 | fn suggest_eliding_single_use_lifetime( | |
1906 | &self, | |
1907 | err: &mut DiagnosticBuilder<'_>, | |
1908 | def_id: DefId, | |
1909 | lifetime: &hir::Lifetime, | |
1910 | ) { | |
1911 | let name = lifetime.name.ident(); | |
5869c6ff XL |
1912 | let remove_decl = self |
1913 | .tcx | |
1914 | .parent(def_id) | |
1915 | .and_then(|parent_def_id| self.tcx.hir().get_generics(parent_def_id)) | |
1916 | .and_then(|generics| self.lifetime_deletion_span(name, generics)); | |
dfeec247 XL |
1917 | |
1918 | let mut remove_use = None; | |
1919 | let mut elide_use = None; | |
1920 | let mut find_arg_use_span = |inputs: &[hir::Ty<'_>]| { | |
1921 | for input in inputs { | |
1922 | match input.kind { | |
1923 | hir::TyKind::Rptr(lt, _) => { | |
1924 | if lt.name.ident() == name { | |
1925 | // include the trailing whitespace between the lifetime and type names | |
1926 | let lt_through_ty_span = lifetime.span.to(input.span.shrink_to_hi()); | |
1927 | remove_use = Some( | |
1928 | self.tcx | |
1929 | .sess | |
1930 | .source_map() | |
1931 | .span_until_non_whitespace(lt_through_ty_span), | |
1932 | ); | |
1933 | break; | |
1934 | } | |
1935 | } | |
1936 | hir::TyKind::Path(ref qpath) => { | |
1937 | if let QPath::Resolved(_, path) = qpath { | |
1938 | let last_segment = &path.segments[path.segments.len() - 1]; | |
5869c6ff | 1939 | let generics = last_segment.args(); |
dfeec247 XL |
1940 | for arg in generics.args.iter() { |
1941 | if let GenericArg::Lifetime(lt) = arg { | |
1942 | if lt.name.ident() == name { | |
1943 | elide_use = Some(lt.span); | |
1944 | break; | |
1945 | } | |
1946 | } | |
1947 | } | |
1948 | break; | |
1949 | } | |
1950 | } | |
1951 | _ => {} | |
1952 | } | |
1953 | } | |
1954 | }; | |
1955 | if let Node::Lifetime(hir_lifetime) = self.tcx.hir().get(lifetime.hir_id) { | |
1956 | if let Some(parent) = | |
1957 | self.tcx.hir().find(self.tcx.hir().get_parent_item(hir_lifetime.hir_id)) | |
1958 | { | |
1959 | match parent { | |
1960 | Node::Item(item) => { | |
1961 | if let hir::ItemKind::Fn(sig, _, _) = &item.kind { | |
1962 | find_arg_use_span(sig.decl.inputs); | |
1963 | } | |
1964 | } | |
1965 | Node::ImplItem(impl_item) => { | |
ba9703b0 | 1966 | if let hir::ImplItemKind::Fn(sig, _) = &impl_item.kind { |
dfeec247 XL |
1967 | find_arg_use_span(sig.decl.inputs); |
1968 | } | |
1969 | } | |
1970 | _ => {} | |
1971 | } | |
1972 | } | |
1973 | } | |
1974 | ||
1975 | let msg = "elide the single-use lifetime"; | |
1976 | match (remove_decl, remove_use, elide_use) { | |
1977 | (Some(decl_span), Some(use_span), None) => { | |
1978 | // if both declaration and use deletion spans start at the same | |
1979 | // place ("start at" because the latter includes trailing | |
1980 | // whitespace), then this is an in-band lifetime | |
1981 | if decl_span.shrink_to_lo() == use_span.shrink_to_lo() { | |
1982 | err.span_suggestion( | |
1983 | use_span, | |
1984 | msg, | |
1985 | String::new(), | |
1986 | Applicability::MachineApplicable, | |
1987 | ); | |
1988 | } else { | |
1989 | err.multipart_suggestion( | |
1990 | msg, | |
1991 | vec![(decl_span, String::new()), (use_span, String::new())], | |
1992 | Applicability::MachineApplicable, | |
1993 | ); | |
1994 | } | |
1995 | } | |
1996 | (Some(decl_span), None, Some(use_span)) => { | |
1997 | err.multipart_suggestion( | |
1998 | msg, | |
1999 | vec![(decl_span, String::new()), (use_span, "'_".to_owned())], | |
2000 | Applicability::MachineApplicable, | |
2001 | ); | |
2002 | } | |
2003 | _ => {} | |
2004 | } | |
2005 | } | |
2006 | ||
2007 | fn check_uses_for_lifetimes_defined_by_scope(&mut self) { | |
2008 | let defined_by = match self.scope { | |
2009 | Scope::Binder { lifetimes, .. } => lifetimes, | |
2010 | _ => { | |
2011 | debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope"); | |
2012 | return; | |
2013 | } | |
2014 | }; | |
2015 | ||
2016 | let mut def_ids: Vec<_> = defined_by | |
2017 | .values() | |
2018 | .flat_map(|region| match region { | |
2019 | Region::EarlyBound(_, def_id, _) | |
cdc7bbd5 | 2020 | | Region::LateBound(_, _, def_id, _) |
dfeec247 XL |
2021 | | Region::Free(_, def_id) => Some(*def_id), |
2022 | ||
2023 | Region::LateBoundAnon(..) | Region::Static => None, | |
2024 | }) | |
2025 | .collect(); | |
2026 | ||
2027 | // ensure that we issue lints in a repeatable order | |
2028 | def_ids.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id)); | |
2029 | ||
c295e0f8 | 2030 | 'lifetimes: for def_id in def_ids { |
dfeec247 XL |
2031 | debug!("check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", def_id); |
2032 | ||
2033 | let lifetimeuseset = self.lifetime_uses.remove(&def_id); | |
2034 | ||
2035 | debug!( | |
2036 | "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}", | |
2037 | lifetimeuseset | |
2038 | ); | |
2039 | ||
2040 | match lifetimeuseset { | |
2041 | Some(LifetimeUseSet::One(lifetime)) => { | |
3dfed10e | 2042 | let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); |
dfeec247 XL |
2043 | debug!("hir id first={:?}", hir_id); |
2044 | if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) { | |
2045 | Node::Lifetime(hir_lifetime) => Some(( | |
2046 | hir_lifetime.hir_id, | |
2047 | hir_lifetime.span, | |
2048 | hir_lifetime.name.ident(), | |
2049 | )), | |
2050 | Node::GenericParam(param) => { | |
2051 | Some((param.hir_id, param.span, param.name.ident())) | |
2052 | } | |
2053 | _ => None, | |
2054 | } { | |
2055 | debug!("id = {:?} span = {:?} name = {:?}", id, span, name); | |
2056 | if name.name == kw::UnderscoreLifetime { | |
2057 | continue; | |
2058 | } | |
2059 | ||
2060 | if let Some(parent_def_id) = self.tcx.parent(def_id) { | |
f9f354fc | 2061 | if let Some(def_id) = parent_def_id.as_local() { |
3dfed10e | 2062 | let parent_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); |
dfeec247 | 2063 | // lifetimes in `derive` expansions don't count (Issue #53738) |
94222f64 XL |
2064 | if self |
2065 | .tcx | |
2066 | .hir() | |
2067 | .attrs(parent_hir_id) | |
2068 | .iter() | |
2069 | .any(|attr| attr.has_name(sym::automatically_derived)) | |
2070 | { | |
dfeec247 XL |
2071 | continue; |
2072 | } | |
c295e0f8 XL |
2073 | |
2074 | // opaque types generated when desugaring an async function can have a single | |
2075 | // use lifetime even if it is explicitly denied (Issue #77175) | |
2076 | if let hir::Node::Item(hir::Item { | |
2077 | kind: hir::ItemKind::OpaqueTy(ref opaque), | |
2078 | .. | |
2079 | }) = self.tcx.hir().get(parent_hir_id) | |
2080 | { | |
2081 | if opaque.origin != hir::OpaqueTyOrigin::AsyncFn { | |
2082 | continue 'lifetimes; | |
2083 | } | |
2084 | // We want to do this only if the liftime identifier is already defined | |
2085 | // in the async function that generated this. Otherwise it could be | |
2086 | // an opaque type defined by the developer and we still want this | |
2087 | // lint to fail compilation | |
2088 | for p in opaque.generics.params { | |
2089 | if defined_by.contains_key(&p.name) { | |
2090 | continue 'lifetimes; | |
2091 | } | |
2092 | } | |
2093 | } | |
dfeec247 XL |
2094 | } |
2095 | } | |
2096 | ||
74b04a01 | 2097 | self.tcx.struct_span_lint_hir( |
dfeec247 XL |
2098 | lint::builtin::SINGLE_USE_LIFETIMES, |
2099 | id, | |
2100 | span, | |
74b04a01 XL |
2101 | |lint| { |
2102 | let mut err = lint.build(&format!( | |
2103 | "lifetime parameter `{}` only used once", | |
2104 | name | |
2105 | )); | |
2106 | if span == lifetime.span { | |
2107 | // spans are the same for in-band lifetime declarations | |
2108 | err.span_label(span, "this lifetime is only used here"); | |
2109 | } else { | |
2110 | err.span_label(span, "this lifetime..."); | |
2111 | err.span_label(lifetime.span, "...is used only here"); | |
2112 | } | |
2113 | self.suggest_eliding_single_use_lifetime( | |
2114 | &mut err, def_id, lifetime, | |
2115 | ); | |
2116 | err.emit(); | |
2117 | }, | |
dfeec247 | 2118 | ); |
dfeec247 XL |
2119 | } |
2120 | } | |
2121 | Some(LifetimeUseSet::Many) => { | |
2122 | debug!("not one use lifetime"); | |
2123 | } | |
2124 | None => { | |
3dfed10e | 2125 | let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); |
dfeec247 XL |
2126 | if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) { |
2127 | Node::Lifetime(hir_lifetime) => Some(( | |
2128 | hir_lifetime.hir_id, | |
2129 | hir_lifetime.span, | |
2130 | hir_lifetime.name.ident(), | |
2131 | )), | |
2132 | Node::GenericParam(param) => { | |
2133 | Some((param.hir_id, param.span, param.name.ident())) | |
2134 | } | |
2135 | _ => None, | |
2136 | } { | |
2137 | debug!("id ={:?} span = {:?} name = {:?}", id, span, name); | |
74b04a01 | 2138 | self.tcx.struct_span_lint_hir( |
dfeec247 XL |
2139 | lint::builtin::UNUSED_LIFETIMES, |
2140 | id, | |
2141 | span, | |
74b04a01 XL |
2142 | |lint| { |
2143 | let mut err = lint | |
2144 | .build(&format!("lifetime parameter `{}` never used", name)); | |
2145 | if let Some(parent_def_id) = self.tcx.parent(def_id) { | |
2146 | if let Some(generics) = | |
2147 | self.tcx.hir().get_generics(parent_def_id) | |
2148 | { | |
2149 | let unused_lt_span = | |
2150 | self.lifetime_deletion_span(name, generics); | |
2151 | if let Some(span) = unused_lt_span { | |
2152 | err.span_suggestion( | |
2153 | span, | |
2154 | "elide the unused lifetime", | |
2155 | String::new(), | |
2156 | Applicability::MachineApplicable, | |
2157 | ); | |
2158 | } | |
2159 | } | |
dfeec247 | 2160 | } |
74b04a01 XL |
2161 | err.emit(); |
2162 | }, | |
2163 | ); | |
dfeec247 XL |
2164 | } |
2165 | } | |
2166 | } | |
2167 | } | |
2168 | } | |
2169 | ||
2170 | /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. | |
2171 | /// | |
2172 | /// Handles visiting fns and methods. These are a bit complicated because we must distinguish | |
2173 | /// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear | |
2174 | /// within type bounds; those are early bound lifetimes, and the rest are late bound. | |
2175 | /// | |
2176 | /// For example: | |
2177 | /// | |
2178 | /// fn foo<'a,'b,'c,T:Trait<'b>>(...) | |
2179 | /// | |
2180 | /// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound | |
2181 | /// lifetimes may be interspersed together. | |
2182 | /// | |
2183 | /// If early bound lifetimes are present, we separate them into their own list (and likewise | |
2184 | /// for late bound). They will be numbered sequentially, starting from the lowest index that is | |
2185 | /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late | |
2186 | /// bound lifetimes are resolved by name and associated with a binder ID (`binder_id`), so the | |
2187 | /// ordering is not important there. | |
2188 | fn visit_early_late<F>( | |
2189 | &mut self, | |
2190 | parent_id: Option<hir::HirId>, | |
cdc7bbd5 | 2191 | hir_id: hir::HirId, |
dfeec247 XL |
2192 | decl: &'tcx hir::FnDecl<'tcx>, |
2193 | generics: &'tcx hir::Generics<'tcx>, | |
2194 | walk: F, | |
2195 | ) where | |
2196 | F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), | |
2197 | { | |
2198 | insert_late_bound_lifetimes(self.map, decl, generics); | |
2199 | ||
2200 | // Find the start of nested early scopes, e.g., in methods. | |
cdc7bbd5 | 2201 | let mut next_early_index = 0; |
dfeec247 XL |
2202 | if let Some(parent_id) = parent_id { |
2203 | let parent = self.tcx.hir().expect_item(parent_id); | |
2204 | if sub_items_have_self_param(&parent.kind) { | |
cdc7bbd5 | 2205 | next_early_index += 1; // Self comes before lifetimes |
dfeec247 XL |
2206 | } |
2207 | match parent.kind { | |
2208 | hir::ItemKind::Trait(_, _, ref generics, ..) | |
5869c6ff | 2209 | | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => { |
cdc7bbd5 | 2210 | next_early_index += generics.params.len() as u32; |
dfeec247 XL |
2211 | } |
2212 | _ => {} | |
2213 | } | |
2214 | } | |
2215 | ||
2216 | let mut non_lifetime_count = 0; | |
cdc7bbd5 | 2217 | let mut named_late_bound_vars = 0; |
17df50a5 | 2218 | let lifetimes: FxIndexMap<hir::ParamName, Region> = generics |
dfeec247 XL |
2219 | .params |
2220 | .iter() | |
2221 | .filter_map(|param| match param.kind { | |
2222 | GenericParamKind::Lifetime { .. } => { | |
2223 | if self.map.late_bound.contains(¶m.hir_id) { | |
cdc7bbd5 XL |
2224 | let late_bound_idx = named_late_bound_vars; |
2225 | named_late_bound_vars += 1; | |
2226 | Some(Region::late(late_bound_idx, &self.tcx.hir(), param)) | |
dfeec247 | 2227 | } else { |
cdc7bbd5 | 2228 | Some(Region::early(&self.tcx.hir(), &mut next_early_index, param)) |
dfeec247 XL |
2229 | } |
2230 | } | |
2231 | GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { | |
2232 | non_lifetime_count += 1; | |
2233 | None | |
2234 | } | |
2235 | }) | |
2236 | .collect(); | |
cdc7bbd5 | 2237 | let next_early_index = next_early_index + non_lifetime_count; |
dfeec247 | 2238 | |
cdc7bbd5 XL |
2239 | let binders: Vec<_> = generics |
2240 | .params | |
2241 | .iter() | |
2242 | .filter_map(|param| match param.kind { | |
2243 | GenericParamKind::Lifetime { .. } | |
2244 | if self.map.late_bound.contains(¶m.hir_id) => | |
2245 | { | |
2246 | Some(param) | |
2247 | } | |
2248 | _ => None, | |
2249 | }) | |
2250 | .enumerate() | |
2251 | .map(|(late_bound_idx, param)| { | |
2252 | let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param); | |
2253 | let r = late_region_as_bound_region(self.tcx, &pair.1); | |
2254 | r | |
2255 | }) | |
2256 | .collect(); | |
2257 | self.map.late_bound_vars.insert(hir_id, binders); | |
dfeec247 | 2258 | let scope = Scope::Binder { |
cdc7bbd5 | 2259 | hir_id, |
dfeec247 XL |
2260 | lifetimes, |
2261 | next_early_index, | |
2262 | s: self.scope, | |
2263 | opaque_type_parent: true, | |
2264 | track_lifetime_uses: false, | |
cdc7bbd5 | 2265 | scope_type: BinderScopeType::Normal, |
dfeec247 XL |
2266 | }; |
2267 | self.with(scope, move |old_scope, this| { | |
2268 | this.check_lifetime_params(old_scope, &generics.params); | |
17df50a5 | 2269 | walk(this); |
dfeec247 XL |
2270 | }); |
2271 | } | |
2272 | ||
2273 | fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 { | |
2274 | let mut scope = self.scope; | |
2275 | loop { | |
2276 | match *scope { | |
2277 | Scope::Root => return 0, | |
2278 | ||
2279 | Scope::Binder { next_early_index, opaque_type_parent, .. } | |
2280 | if (!only_opaque_type_parent || opaque_type_parent) => | |
2281 | { | |
2282 | return next_early_index; | |
2283 | } | |
2284 | ||
2285 | Scope::Binder { s, .. } | |
2286 | | Scope::Body { s, .. } | |
2287 | | Scope::Elision { s, .. } | |
cdc7bbd5 XL |
2288 | | Scope::ObjectLifetimeDefault { s, .. } |
2289 | | Scope::Supertrait { s, .. } | |
2290 | | Scope::TraitRefBoundary { s, .. } => scope = s, | |
dfeec247 XL |
2291 | } |
2292 | } | |
2293 | } | |
2294 | ||
2295 | /// Returns the next index one would use for an early-bound-region | |
2296 | /// if extending the current scope. | |
2297 | fn next_early_index(&self) -> u32 { | |
2298 | self.next_early_index_helper(true) | |
2299 | } | |
2300 | ||
2301 | /// Returns the next index one would use for an `impl Trait` that | |
2302 | /// is being converted into an opaque type alias `impl Trait`. This will be the | |
2303 | /// next early index from the enclosing item, for the most | |
2304 | /// part. See the `opaque_type_parent` field for more info. | |
2305 | fn next_early_index_for_opaque_type(&self) -> u32 { | |
2306 | self.next_early_index_helper(false) | |
2307 | } | |
2308 | ||
2309 | fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) { | |
2310 | debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref); | |
2311 | ||
2312 | // If we've already reported an error, just ignore `lifetime_ref`. | |
2313 | if let LifetimeName::Error = lifetime_ref.name { | |
2314 | return; | |
2315 | } | |
2316 | ||
2317 | // Walk up the scope chain, tracking the number of fn scopes | |
2318 | // that we pass through, until we find a lifetime with the | |
2319 | // given name or we run out of scopes. | |
2320 | // search. | |
2321 | let mut late_depth = 0; | |
2322 | let mut scope = self.scope; | |
2323 | let mut outermost_body = None; | |
2324 | let result = loop { | |
2325 | match *scope { | |
2326 | Scope::Body { id, s } => { | |
5869c6ff | 2327 | // Non-static lifetimes are prohibited in anonymous constants without |
94222f64 | 2328 | // `generic_const_exprs`. |
1b1a35ee XL |
2329 | self.maybe_emit_forbidden_non_static_lifetime_error(id, lifetime_ref); |
2330 | ||
dfeec247 XL |
2331 | outermost_body = Some(id); |
2332 | scope = s; | |
2333 | } | |
2334 | ||
2335 | Scope::Root => { | |
2336 | break None; | |
2337 | } | |
2338 | ||
cdc7bbd5 | 2339 | Scope::Binder { ref lifetimes, scope_type, s, .. } => { |
dfeec247 XL |
2340 | match lifetime_ref.name { |
2341 | LifetimeName::Param(param_name) => { | |
ba9703b0 XL |
2342 | if let Some(&def) = lifetimes.get(¶m_name.normalize_to_macros_2_0()) |
2343 | { | |
dfeec247 XL |
2344 | break Some(def.shifted(late_depth)); |
2345 | } | |
2346 | } | |
2347 | _ => bug!("expected LifetimeName::Param"), | |
2348 | } | |
cdc7bbd5 XL |
2349 | match scope_type { |
2350 | BinderScopeType::Normal => late_depth += 1, | |
2351 | BinderScopeType::Concatenating => {} | |
2352 | } | |
dfeec247 XL |
2353 | scope = s; |
2354 | } | |
2355 | ||
cdc7bbd5 XL |
2356 | Scope::Elision { s, .. } |
2357 | | Scope::ObjectLifetimeDefault { s, .. } | |
2358 | | Scope::Supertrait { s, .. } | |
2359 | | Scope::TraitRefBoundary { s, .. } => { | |
dfeec247 XL |
2360 | scope = s; |
2361 | } | |
2362 | } | |
2363 | }; | |
2364 | ||
2365 | if let Some(mut def) = result { | |
2366 | if let Region::EarlyBound(..) = def { | |
2367 | // Do not free early-bound regions, only late-bound ones. | |
2368 | } else if let Some(body_id) = outermost_body { | |
2369 | let fn_id = self.tcx.hir().body_owner(body_id); | |
2370 | match self.tcx.hir().get(fn_id) { | |
2371 | Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. }) | |
2372 | | Node::TraitItem(&hir::TraitItem { | |
ba9703b0 | 2373 | kind: hir::TraitItemKind::Fn(..), .. |
dfeec247 | 2374 | }) |
ba9703b0 | 2375 | | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => { |
dfeec247 | 2376 | let scope = self.tcx.hir().local_def_id(fn_id); |
f9f354fc | 2377 | def = Region::Free(scope.to_def_id(), def.id().unwrap()); |
dfeec247 XL |
2378 | } |
2379 | _ => {} | |
2380 | } | |
2381 | } | |
2382 | ||
2383 | // Check for fn-syntax conflicts with in-band lifetime definitions | |
cdc7bbd5 | 2384 | if !self.trait_definition_only && self.is_in_fn_syntax { |
dfeec247 XL |
2385 | match def { |
2386 | Region::EarlyBound(_, _, LifetimeDefOrigin::InBand) | |
cdc7bbd5 | 2387 | | Region::LateBound(_, _, _, LifetimeDefOrigin::InBand) => { |
dfeec247 XL |
2388 | struct_span_err!( |
2389 | self.tcx.sess, | |
2390 | lifetime_ref.span, | |
2391 | E0687, | |
2392 | "lifetimes used in `fn` or `Fn` syntax must be \ | |
2393 | explicitly declared using `<...>` binders" | |
2394 | ) | |
2395 | .span_label(lifetime_ref.span, "in-band lifetime definition") | |
2396 | .emit(); | |
2397 | } | |
2398 | ||
2399 | Region::Static | |
ba9703b0 XL |
2400 | | Region::EarlyBound( |
2401 | _, | |
2402 | _, | |
2403 | LifetimeDefOrigin::ExplicitOrElided | LifetimeDefOrigin::Error, | |
2404 | ) | |
2405 | | Region::LateBound( | |
cdc7bbd5 | 2406 | _, |
ba9703b0 XL |
2407 | _, |
2408 | _, | |
2409 | LifetimeDefOrigin::ExplicitOrElided | LifetimeDefOrigin::Error, | |
2410 | ) | |
dfeec247 XL |
2411 | | Region::LateBoundAnon(..) |
2412 | | Region::Free(..) => {} | |
2413 | } | |
2414 | } | |
2415 | ||
2416 | self.insert_lifetime(lifetime_ref, def); | |
2417 | } else { | |
74b04a01 | 2418 | self.emit_undeclared_lifetime_error(lifetime_ref); |
dfeec247 XL |
2419 | } |
2420 | } | |
2421 | ||
2422 | fn visit_segment_args( | |
2423 | &mut self, | |
2424 | res: Res, | |
2425 | depth: usize, | |
2426 | generic_args: &'tcx hir::GenericArgs<'tcx>, | |
2427 | ) { | |
2428 | debug!( | |
2429 | "visit_segment_args(res={:?}, depth={:?}, generic_args={:?})", | |
2430 | res, depth, generic_args, | |
2431 | ); | |
2432 | ||
2433 | if generic_args.parenthesized { | |
2434 | let was_in_fn_syntax = self.is_in_fn_syntax; | |
2435 | self.is_in_fn_syntax = true; | |
2436 | self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty())); | |
2437 | self.is_in_fn_syntax = was_in_fn_syntax; | |
2438 | return; | |
2439 | } | |
2440 | ||
2441 | let mut elide_lifetimes = true; | |
cdc7bbd5 | 2442 | let lifetimes: Vec<_> = generic_args |
dfeec247 XL |
2443 | .args |
2444 | .iter() | |
2445 | .filter_map(|arg| match arg { | |
2446 | hir::GenericArg::Lifetime(lt) => { | |
2447 | if !lt.is_elided() { | |
2448 | elide_lifetimes = false; | |
2449 | } | |
2450 | Some(lt) | |
2451 | } | |
2452 | _ => None, | |
2453 | }) | |
2454 | .collect(); | |
cdc7bbd5 XL |
2455 | // We short-circuit here if all are elided in order to pluralize |
2456 | // possible errors | |
dfeec247 | 2457 | if elide_lifetimes { |
cdc7bbd5 | 2458 | self.resolve_elided_lifetimes(&lifetimes); |
dfeec247 XL |
2459 | } else { |
2460 | lifetimes.iter().for_each(|lt| self.visit_lifetime(lt)); | |
2461 | } | |
2462 | ||
2463 | // Figure out if this is a type/trait segment, | |
2464 | // which requires object lifetime defaults. | |
2465 | let parent_def_id = |this: &mut Self, def_id: DefId| { | |
2466 | let def_key = this.tcx.def_key(def_id); | |
2467 | DefId { krate: def_id.krate, index: def_key.parent.expect("missing parent") } | |
2468 | }; | |
2469 | let type_def_id = match res { | |
2470 | Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(parent_def_id(self, def_id)), | |
2471 | Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(parent_def_id(self, def_id)), | |
ba9703b0 XL |
2472 | Res::Def( |
2473 | DefKind::Struct | |
2474 | | DefKind::Union | |
2475 | | DefKind::Enum | |
2476 | | DefKind::TyAlias | |
2477 | | DefKind::Trait, | |
2478 | def_id, | |
2479 | ) if depth == 0 => Some(def_id), | |
dfeec247 XL |
2480 | _ => None, |
2481 | }; | |
2482 | ||
2483 | debug!("visit_segment_args: type_def_id={:?}", type_def_id); | |
2484 | ||
2485 | // Compute a vector of defaults, one for each type parameter, | |
2486 | // per the rules given in RFCs 599 and 1156. Example: | |
2487 | // | |
2488 | // ```rust | |
2489 | // struct Foo<'a, T: 'a, U> { } | |
2490 | // ``` | |
2491 | // | |
2492 | // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default | |
2493 | // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) | |
2494 | // and `dyn Baz` to `dyn Baz + 'static` (because there is no | |
2495 | // such bound). | |
2496 | // | |
2497 | // Therefore, we would compute `object_lifetime_defaults` to a | |
2498 | // vector like `['x, 'static]`. Note that the vector only | |
2499 | // includes type parameters. | |
6a06907d | 2500 | let object_lifetime_defaults = type_def_id.map_or_else(Vec::new, |def_id| { |
dfeec247 XL |
2501 | let in_body = { |
2502 | let mut scope = self.scope; | |
2503 | loop { | |
2504 | match *scope { | |
2505 | Scope::Root => break false, | |
2506 | ||
2507 | Scope::Body { .. } => break true, | |
2508 | ||
2509 | Scope::Binder { s, .. } | |
2510 | | Scope::Elision { s, .. } | |
cdc7bbd5 XL |
2511 | | Scope::ObjectLifetimeDefault { s, .. } |
2512 | | Scope::Supertrait { s, .. } | |
2513 | | Scope::TraitRefBoundary { s, .. } => { | |
dfeec247 XL |
2514 | scope = s; |
2515 | } | |
2516 | } | |
2517 | } | |
2518 | }; | |
2519 | ||
2520 | let map = &self.map; | |
cdc7bbd5 XL |
2521 | let set_to_region = |set: &ObjectLifetimeDefault| match *set { |
2522 | Set1::Empty => { | |
2523 | if in_body { | |
2524 | None | |
2525 | } else { | |
2526 | Some(Region::Static) | |
2527 | } | |
2528 | } | |
2529 | Set1::One(r) => { | |
2530 | let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { | |
2531 | GenericArg::Lifetime(lt) => Some(lt), | |
2532 | _ => None, | |
2533 | }); | |
2534 | r.subst(lifetimes, map) | |
2535 | } | |
2536 | Set1::Many => None, | |
2537 | }; | |
2538 | if let Some(def_id) = def_id.as_local() { | |
3dfed10e | 2539 | let id = self.tcx.hir().local_def_id_to_hir_id(def_id); |
cdc7bbd5 | 2540 | self.tcx.object_lifetime_defaults(id).unwrap().iter().map(set_to_region).collect() |
dfeec247 XL |
2541 | } else { |
2542 | let tcx = self.tcx; | |
cdc7bbd5 XL |
2543 | self.xcrate_object_lifetime_defaults |
2544 | .entry(def_id) | |
2545 | .or_insert_with(|| { | |
2546 | tcx.generics_of(def_id) | |
2547 | .params | |
2548 | .iter() | |
2549 | .filter_map(|param| match param.kind { | |
2550 | GenericParamDefKind::Type { object_lifetime_default, .. } => { | |
2551 | Some(object_lifetime_default) | |
2552 | } | |
2553 | GenericParamDefKind::Lifetime | |
2554 | | GenericParamDefKind::Const { .. } => None, | |
2555 | }) | |
2556 | .collect() | |
2557 | }) | |
2558 | .iter() | |
2559 | .map(set_to_region) | |
2560 | .collect() | |
2561 | } | |
dfeec247 XL |
2562 | }); |
2563 | ||
2564 | debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults); | |
2565 | ||
2566 | let mut i = 0; | |
2567 | for arg in generic_args.args { | |
2568 | match arg { | |
2569 | GenericArg::Lifetime(_) => {} | |
2570 | GenericArg::Type(ty) => { | |
2571 | if let Some(<) = object_lifetime_defaults.get(i) { | |
2572 | let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; | |
2573 | self.with(scope, |_, this| this.visit_ty(ty)); | |
2574 | } else { | |
2575 | self.visit_ty(ty); | |
2576 | } | |
2577 | i += 1; | |
2578 | } | |
2579 | GenericArg::Const(ct) => { | |
2580 | self.visit_anon_const(&ct.value); | |
2581 | } | |
94222f64 XL |
2582 | GenericArg::Infer(inf) => { |
2583 | self.visit_id(inf.hir_id); | |
2584 | if inf.kind.is_type() { | |
2585 | i += 1; | |
2586 | } | |
2587 | } | |
dfeec247 XL |
2588 | } |
2589 | } | |
2590 | ||
2591 | // Hack: when resolving the type `XX` in binding like `dyn | |
2592 | // Foo<'b, Item = XX>`, the current object-lifetime default | |
2593 | // would be to examine the trait `Foo` to check whether it has | |
2594 | // a lifetime bound declared on `Item`. e.g., if `Foo` is | |
2595 | // declared like so, then the default object lifetime bound in | |
2596 | // `XX` should be `'b`: | |
2597 | // | |
2598 | // ```rust | |
2599 | // trait Foo<'a> { | |
2600 | // type Item: 'a; | |
2601 | // } | |
2602 | // ``` | |
2603 | // | |
2604 | // but if we just have `type Item;`, then it would be | |
2605 | // `'static`. However, we don't get all of this logic correct. | |
2606 | // | |
2607 | // Instead, we do something hacky: if there are no lifetime parameters | |
2608 | // to the trait, then we simply use a default object lifetime | |
2609 | // bound of `'static`, because there is no other possibility. On the other hand, | |
2610 | // if there ARE lifetime parameters, then we require the user to give an | |
2611 | // explicit bound for now. | |
2612 | // | |
2613 | // This is intended to leave room for us to implement the | |
2614 | // correct behavior in the future. | |
29967ef6 XL |
2615 | let has_lifetime_parameter = |
2616 | generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))); | |
dfeec247 | 2617 | |
cdc7bbd5 XL |
2618 | // Resolve lifetimes found in the bindings, so either in the type `XX` in `Item = XX` or |
2619 | // in the trait ref `YY<...>` in `Item: YY<...>`. | |
2620 | for binding in generic_args.bindings { | |
dfeec247 XL |
2621 | let scope = Scope::ObjectLifetimeDefault { |
2622 | lifetime: if has_lifetime_parameter { None } else { Some(Region::Static) }, | |
2623 | s: self.scope, | |
2624 | }; | |
cdc7bbd5 XL |
2625 | if let Some(type_def_id) = type_def_id { |
2626 | let lifetimes = LifetimeContext::supertrait_hrtb_lifetimes( | |
2627 | self.tcx, | |
2628 | type_def_id, | |
2629 | binding.ident, | |
2630 | ); | |
2631 | self.with(scope, |_, this| { | |
94222f64 XL |
2632 | let scope = Scope::Supertrait { |
2633 | lifetimes: lifetimes.unwrap_or_default(), | |
2634 | s: this.scope, | |
2635 | }; | |
cdc7bbd5 XL |
2636 | this.with(scope, |_, this| this.visit_assoc_type_binding(binding)); |
2637 | }); | |
2638 | } else { | |
2639 | self.with(scope, |_, this| this.visit_assoc_type_binding(binding)); | |
2640 | } | |
2641 | } | |
2642 | } | |
2643 | ||
2644 | /// Returns all the late-bound vars that come into scope from supertrait HRTBs, based on the | |
2645 | /// associated type name and starting trait. | |
2646 | /// For example, imagine we have | |
2647 | /// ```rust | |
2648 | /// trait Foo<'a, 'b> { | |
2649 | /// type As; | |
2650 | /// } | |
2651 | /// trait Bar<'b>: for<'a> Foo<'a, 'b> {} | |
2652 | /// trait Bar: for<'b> Bar<'b> {} | |
2653 | /// ``` | |
2654 | /// In this case, if we wanted to the supertrait HRTB lifetimes for `As` on | |
2655 | /// the starting trait `Bar`, we would return `Some(['b, 'a])`. | |
2656 | fn supertrait_hrtb_lifetimes( | |
2657 | tcx: TyCtxt<'tcx>, | |
2658 | def_id: DefId, | |
2659 | assoc_name: Ident, | |
2660 | ) -> Option<Vec<ty::BoundVariableKind>> { | |
2661 | let trait_defines_associated_type_named = |trait_def_id: DefId| { | |
2662 | tcx.associated_items(trait_def_id) | |
2663 | .find_by_name_and_kind(tcx, assoc_name, ty::AssocKind::Type, trait_def_id) | |
2664 | .is_some() | |
2665 | }; | |
2666 | ||
2667 | use smallvec::{smallvec, SmallVec}; | |
2668 | let mut stack: SmallVec<[(DefId, SmallVec<[ty::BoundVariableKind; 8]>); 8]> = | |
2669 | smallvec![(def_id, smallvec![])]; | |
2670 | let mut visited: FxHashSet<DefId> = FxHashSet::default(); | |
2671 | loop { | |
2672 | let (def_id, bound_vars) = match stack.pop() { | |
2673 | Some(next) => next, | |
2674 | None => break None, | |
2675 | }; | |
2676 | // See issue #83753. If someone writes an associated type on a non-trait, just treat it as | |
2677 | // there being no supertrait HRTBs. | |
2678 | match tcx.def_kind(def_id) { | |
2679 | DefKind::Trait | DefKind::TraitAlias | DefKind::Impl => {} | |
2680 | _ => break None, | |
2681 | } | |
2682 | ||
2683 | if trait_defines_associated_type_named(def_id) { | |
2684 | break Some(bound_vars.into_iter().collect()); | |
2685 | } | |
2686 | let predicates = | |
2687 | tcx.super_predicates_that_define_assoc_type((def_id, Some(assoc_name))); | |
2688 | let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { | |
2689 | let bound_predicate = pred.kind(); | |
2690 | match bound_predicate.skip_binder() { | |
94222f64 | 2691 | ty::PredicateKind::Trait(data) => { |
cdc7bbd5 XL |
2692 | // The order here needs to match what we would get from `subst_supertrait` |
2693 | let pred_bound_vars = bound_predicate.bound_vars(); | |
2694 | let mut all_bound_vars = bound_vars.clone(); | |
2695 | all_bound_vars.extend(pred_bound_vars.iter()); | |
2696 | let super_def_id = data.trait_ref.def_id; | |
2697 | Some((super_def_id, all_bound_vars)) | |
2698 | } | |
2699 | _ => None, | |
2700 | } | |
2701 | }); | |
2702 | ||
2703 | let obligations = obligations.filter(|o| visited.insert(o.0)); | |
2704 | stack.extend(obligations); | |
dfeec247 XL |
2705 | } |
2706 | } | |
2707 | ||
cdc7bbd5 | 2708 | #[tracing::instrument(level = "debug", skip(self))] |
dfeec247 XL |
2709 | fn visit_fn_like_elision( |
2710 | &mut self, | |
2711 | inputs: &'tcx [hir::Ty<'tcx>], | |
2712 | output: Option<&'tcx hir::Ty<'tcx>>, | |
2713 | ) { | |
2714 | debug!("visit_fn_like_elision: enter"); | |
cdc7bbd5 XL |
2715 | let mut scope = &*self.scope; |
2716 | let hir_id = loop { | |
2717 | match scope { | |
2718 | Scope::Binder { hir_id, .. } => { | |
2719 | break *hir_id; | |
2720 | } | |
cdc7bbd5 XL |
2721 | Scope::ObjectLifetimeDefault { ref s, .. } |
2722 | | Scope::Elision { ref s, .. } | |
2723 | | Scope::Supertrait { ref s, .. } | |
2724 | | Scope::TraitRefBoundary { ref s, .. } => { | |
2725 | scope = *s; | |
2726 | } | |
94222f64 XL |
2727 | Scope::Root | Scope::Body { .. } => { |
2728 | // See issues #83907 and #83693. Just bail out from looking inside. | |
cdc7bbd5 XL |
2729 | self.tcx.sess.delay_span_bug( |
2730 | rustc_span::DUMMY_SP, | |
2731 | "In fn_like_elision without appropriate scope above", | |
2732 | ); | |
2733 | return; | |
2734 | } | |
2735 | } | |
2736 | }; | |
2737 | // While not strictly necessary, we gather anon lifetimes *before* actually | |
2738 | // visiting the argument types. | |
2739 | let mut gather = GatherAnonLifetimes { anon_count: 0 }; | |
2740 | for input in inputs { | |
2741 | gather.visit_ty(input); | |
2742 | } | |
c295e0f8 | 2743 | trace!(?gather.anon_count); |
cdc7bbd5 XL |
2744 | let late_bound_vars = self.map.late_bound_vars.entry(hir_id).or_default(); |
2745 | let named_late_bound_vars = late_bound_vars.len() as u32; | |
2746 | late_bound_vars.extend( | |
2747 | (0..gather.anon_count).map(|var| ty::BoundVariableKind::Region(ty::BrAnon(var))), | |
2748 | ); | |
2749 | let arg_scope = Scope::Elision { | |
2750 | elide: Elide::FreshLateAnon(named_late_bound_vars, Cell::new(0)), | |
2751 | s: self.scope, | |
2752 | }; | |
dfeec247 XL |
2753 | self.with(arg_scope, |_, this| { |
2754 | for input in inputs { | |
2755 | this.visit_ty(input); | |
2756 | } | |
dfeec247 XL |
2757 | }); |
2758 | ||
2759 | let output = match output { | |
2760 | Some(ty) => ty, | |
2761 | None => return, | |
2762 | }; | |
2763 | ||
cdc7bbd5 | 2764 | debug!("determine output"); |
dfeec247 XL |
2765 | |
2766 | // Figure out if there's a body we can get argument names from, | |
2767 | // and whether there's a `self` argument (treated specially). | |
2768 | let mut assoc_item_kind = None; | |
2769 | let mut impl_self = None; | |
2770 | let parent = self.tcx.hir().get_parent_node(output.hir_id); | |
2771 | let body = match self.tcx.hir().get(parent) { | |
2772 | // `fn` definitions and methods. | |
2773 | Node::Item(&hir::Item { kind: hir::ItemKind::Fn(.., body), .. }) => Some(body), | |
2774 | ||
ba9703b0 | 2775 | Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(_, ref m), .. }) => { |
dfeec247 XL |
2776 | if let hir::ItemKind::Trait(.., ref trait_items) = |
2777 | self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind | |
2778 | { | |
2779 | assoc_item_kind = | |
6a06907d | 2780 | trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind); |
dfeec247 XL |
2781 | } |
2782 | match *m { | |
ba9703b0 XL |
2783 | hir::TraitFn::Required(_) => None, |
2784 | hir::TraitFn::Provided(body) => Some(body), | |
dfeec247 XL |
2785 | } |
2786 | } | |
2787 | ||
ba9703b0 | 2788 | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) => { |
5869c6ff | 2789 | if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) = |
dfeec247 XL |
2790 | self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind |
2791 | { | |
2792 | impl_self = Some(self_ty); | |
2793 | assoc_item_kind = | |
6a06907d | 2794 | items.iter().find(|ii| ii.id.hir_id() == parent).map(|ii| ii.kind); |
dfeec247 XL |
2795 | } |
2796 | Some(body) | |
2797 | } | |
2798 | ||
2799 | // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds). | |
2800 | Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None, | |
2801 | // Everything else (only closures?) doesn't | |
2802 | // actually enjoy elision in return types. | |
2803 | _ => { | |
2804 | self.visit_ty(output); | |
2805 | return; | |
2806 | } | |
2807 | }; | |
2808 | ||
2809 | let has_self = match assoc_item_kind { | |
ba9703b0 | 2810 | Some(hir::AssocItemKind::Fn { has_self }) => has_self, |
dfeec247 XL |
2811 | _ => false, |
2812 | }; | |
2813 | ||
2814 | // In accordance with the rules for lifetime elision, we can determine | |
2815 | // what region to use for elision in the output type in two ways. | |
2816 | // First (determined here), if `self` is by-reference, then the | |
2817 | // implied output region is the region of the self parameter. | |
2818 | if has_self { | |
2819 | struct SelfVisitor<'a> { | |
2820 | map: &'a NamedRegionMap, | |
2821 | impl_self: Option<&'a hir::TyKind<'a>>, | |
2822 | lifetime: Set1<Region>, | |
2823 | } | |
2824 | ||
2825 | impl SelfVisitor<'_> { | |
2826 | // Look for `self: &'a Self` - also desugared from `&'a self`, | |
2827 | // and if that matches, use it for elision and return early. | |
2828 | fn is_self_ty(&self, res: Res) -> bool { | |
2829 | if let Res::SelfTy(..) = res { | |
2830 | return true; | |
2831 | } | |
2832 | ||
2833 | // Can't always rely on literal (or implied) `Self` due | |
2834 | // to the way elision rules were originally specified. | |
2835 | if let Some(&hir::TyKind::Path(hir::QPath::Resolved(None, ref path))) = | |
2836 | self.impl_self | |
2837 | { | |
2838 | match path.res { | |
f035d41b | 2839 | // Permit the types that unambiguously always |
dfeec247 XL |
2840 | // result in the same type constructor being used |
2841 | // (it can't differ between `Self` and `self`). | |
ba9703b0 | 2842 | Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _) |
dfeec247 XL |
2843 | | Res::PrimTy(_) => return res == path.res, |
2844 | _ => {} | |
2845 | } | |
2846 | } | |
2847 | ||
2848 | false | |
2849 | } | |
2850 | } | |
2851 | ||
2852 | impl<'a> Visitor<'a> for SelfVisitor<'a> { | |
ba9703b0 | 2853 | type Map = intravisit::ErasedMap<'a>; |
dfeec247 | 2854 | |
ba9703b0 | 2855 | fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
dfeec247 XL |
2856 | NestedVisitorMap::None |
2857 | } | |
2858 | ||
2859 | fn visit_ty(&mut self, ty: &'a hir::Ty<'a>) { | |
2860 | if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.kind { | |
2861 | if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.kind | |
2862 | { | |
2863 | if self.is_self_ty(path.res) { | |
2864 | if let Some(lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { | |
2865 | self.lifetime.insert(*lifetime); | |
2866 | } | |
2867 | } | |
2868 | } | |
2869 | } | |
2870 | intravisit::walk_ty(self, ty) | |
2871 | } | |
2872 | } | |
2873 | ||
2874 | let mut visitor = SelfVisitor { | |
2875 | map: self.map, | |
2876 | impl_self: impl_self.map(|ty| &ty.kind), | |
2877 | lifetime: Set1::Empty, | |
2878 | }; | |
2879 | visitor.visit_ty(&inputs[0]); | |
2880 | if let Set1::One(lifetime) = visitor.lifetime { | |
2881 | let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope }; | |
2882 | self.with(scope, |_, this| this.visit_ty(output)); | |
2883 | return; | |
2884 | } | |
2885 | } | |
2886 | ||
2887 | // Second, if there was exactly one lifetime (either a substitution or a | |
2888 | // reference) in the arguments, then any anonymous regions in the output | |
2889 | // have that lifetime. | |
2890 | let mut possible_implied_output_region = None; | |
2891 | let mut lifetime_count = 0; | |
2892 | let arg_lifetimes = inputs | |
2893 | .iter() | |
2894 | .enumerate() | |
2895 | .skip(has_self as usize) | |
2896 | .map(|(i, input)| { | |
2897 | let mut gather = GatherLifetimes { | |
2898 | map: self.map, | |
2899 | outer_index: ty::INNERMOST, | |
2900 | have_bound_regions: false, | |
2901 | lifetimes: Default::default(), | |
2902 | }; | |
2903 | gather.visit_ty(input); | |
2904 | ||
2905 | lifetime_count += gather.lifetimes.len(); | |
2906 | ||
2907 | if lifetime_count == 1 && gather.lifetimes.len() == 1 { | |
2908 | // there's a chance that the unique lifetime of this | |
2909 | // iteration will be the appropriate lifetime for output | |
2910 | // parameters, so lets store it. | |
2911 | possible_implied_output_region = gather.lifetimes.iter().cloned().next(); | |
2912 | } | |
2913 | ||
2914 | ElisionFailureInfo { | |
2915 | parent: body, | |
2916 | index: i, | |
2917 | lifetime_count: gather.lifetimes.len(), | |
2918 | have_bound_regions: gather.have_bound_regions, | |
74b04a01 | 2919 | span: input.span, |
dfeec247 XL |
2920 | } |
2921 | }) | |
2922 | .collect(); | |
2923 | ||
2924 | let elide = if lifetime_count == 1 { | |
2925 | Elide::Exact(possible_implied_output_region.unwrap()) | |
2926 | } else { | |
2927 | Elide::Error(arg_lifetimes) | |
2928 | }; | |
2929 | ||
cdc7bbd5 | 2930 | debug!(?elide); |
dfeec247 XL |
2931 | |
2932 | let scope = Scope::Elision { elide, s: self.scope }; | |
2933 | self.with(scope, |_, this| this.visit_ty(output)); | |
dfeec247 XL |
2934 | |
2935 | struct GatherLifetimes<'a> { | |
2936 | map: &'a NamedRegionMap, | |
2937 | outer_index: ty::DebruijnIndex, | |
2938 | have_bound_regions: bool, | |
2939 | lifetimes: FxHashSet<Region>, | |
2940 | } | |
2941 | ||
2942 | impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> { | |
ba9703b0 | 2943 | type Map = intravisit::ErasedMap<'v>; |
dfeec247 | 2944 | |
ba9703b0 | 2945 | fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
dfeec247 XL |
2946 | NestedVisitorMap::None |
2947 | } | |
2948 | ||
2949 | fn visit_ty(&mut self, ty: &hir::Ty<'_>) { | |
2950 | if let hir::TyKind::BareFn(_) = ty.kind { | |
2951 | self.outer_index.shift_in(1); | |
2952 | } | |
2953 | match ty.kind { | |
6a06907d | 2954 | hir::TyKind::TraitObject(bounds, ref lifetime, _) => { |
dfeec247 XL |
2955 | for bound in bounds { |
2956 | self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); | |
2957 | } | |
2958 | ||
2959 | // Stay on the safe side and don't include the object | |
2960 | // lifetime default (which may not end up being used). | |
2961 | if !lifetime.is_elided() { | |
2962 | self.visit_lifetime(lifetime); | |
2963 | } | |
2964 | } | |
2965 | _ => { | |
2966 | intravisit::walk_ty(self, ty); | |
2967 | } | |
2968 | } | |
2969 | if let hir::TyKind::BareFn(_) = ty.kind { | |
2970 | self.outer_index.shift_out(1); | |
2971 | } | |
2972 | } | |
2973 | ||
2974 | fn visit_generic_param(&mut self, param: &hir::GenericParam<'_>) { | |
2975 | if let hir::GenericParamKind::Lifetime { .. } = param.kind { | |
2976 | // FIXME(eddyb) Do we want this? It only makes a difference | |
2977 | // if this `for<'a>` lifetime parameter is never used. | |
2978 | self.have_bound_regions = true; | |
2979 | } | |
2980 | ||
2981 | intravisit::walk_generic_param(self, param); | |
2982 | } | |
2983 | ||
2984 | fn visit_poly_trait_ref( | |
2985 | &mut self, | |
2986 | trait_ref: &hir::PolyTraitRef<'_>, | |
2987 | modifier: hir::TraitBoundModifier, | |
2988 | ) { | |
2989 | self.outer_index.shift_in(1); | |
2990 | intravisit::walk_poly_trait_ref(self, trait_ref, modifier); | |
2991 | self.outer_index.shift_out(1); | |
2992 | } | |
2993 | ||
3dfed10e XL |
2994 | fn visit_param_bound(&mut self, bound: &hir::GenericBound<'_>) { |
2995 | if let hir::GenericBound::LangItemTrait { .. } = bound { | |
2996 | self.outer_index.shift_in(1); | |
2997 | intravisit::walk_param_bound(self, bound); | |
2998 | self.outer_index.shift_out(1); | |
2999 | } else { | |
3000 | intravisit::walk_param_bound(self, bound); | |
3001 | } | |
3002 | } | |
3003 | ||
dfeec247 XL |
3004 | fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { |
3005 | if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { | |
3006 | match lifetime { | |
cdc7bbd5 XL |
3007 | Region::LateBound(debruijn, _, _, _) |
3008 | | Region::LateBoundAnon(debruijn, _, _) | |
dfeec247 XL |
3009 | if debruijn < self.outer_index => |
3010 | { | |
3011 | self.have_bound_regions = true; | |
3012 | } | |
3013 | _ => { | |
cdc7bbd5 | 3014 | // FIXME(jackh726): nested trait refs? |
dfeec247 XL |
3015 | self.lifetimes.insert(lifetime.shifted_out_to_binder(self.outer_index)); |
3016 | } | |
3017 | } | |
3018 | } | |
3019 | } | |
3020 | } | |
cdc7bbd5 XL |
3021 | |
3022 | struct GatherAnonLifetimes { | |
3023 | anon_count: u32, | |
3024 | } | |
3025 | impl<'v> Visitor<'v> for GatherAnonLifetimes { | |
3026 | type Map = intravisit::ErasedMap<'v>; | |
3027 | ||
3028 | fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { | |
3029 | NestedVisitorMap::None | |
3030 | } | |
3031 | ||
c295e0f8 | 3032 | #[instrument(skip(self), level = "trace")] |
cdc7bbd5 XL |
3033 | fn visit_ty(&mut self, ty: &hir::Ty<'_>) { |
3034 | // If we enter a `BareFn`, then we enter a *new* binding scope | |
3035 | if let hir::TyKind::BareFn(_) = ty.kind { | |
3036 | return; | |
3037 | } | |
3038 | intravisit::walk_ty(self, ty); | |
3039 | } | |
3040 | ||
3041 | fn visit_generic_args( | |
3042 | &mut self, | |
3043 | path_span: Span, | |
3044 | generic_args: &'v hir::GenericArgs<'v>, | |
3045 | ) { | |
3046 | // parenthesized args enter a new elison scope | |
3047 | if generic_args.parenthesized { | |
3048 | return; | |
3049 | } | |
3050 | intravisit::walk_generic_args(self, path_span, generic_args) | |
3051 | } | |
3052 | ||
c295e0f8 | 3053 | #[instrument(skip(self), level = "trace")] |
cdc7bbd5 XL |
3054 | fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { |
3055 | if lifetime_ref.is_elided() { | |
3056 | self.anon_count += 1; | |
3057 | } | |
3058 | } | |
3059 | } | |
dfeec247 XL |
3060 | } |
3061 | ||
cdc7bbd5 | 3062 | fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) { |
dfeec247 XL |
3063 | debug!("resolve_elided_lifetimes(lifetime_refs={:?})", lifetime_refs); |
3064 | ||
3065 | if lifetime_refs.is_empty() { | |
3066 | return; | |
3067 | } | |
3068 | ||
dfeec247 XL |
3069 | let mut late_depth = 0; |
3070 | let mut scope = self.scope; | |
3071 | let mut lifetime_names = FxHashSet::default(); | |
3dfed10e | 3072 | let mut lifetime_spans = vec![]; |
dfeec247 XL |
3073 | let error = loop { |
3074 | match *scope { | |
3075 | // Do not assign any resolution, it will be inferred. | |
3076 | Scope::Body { .. } => return, | |
3077 | ||
3078 | Scope::Root => break None, | |
3079 | ||
cdc7bbd5 | 3080 | Scope::Binder { s, ref lifetimes, scope_type, .. } => { |
dfeec247 XL |
3081 | // collect named lifetimes for suggestions |
3082 | for name in lifetimes.keys() { | |
3083 | if let hir::ParamName::Plain(name) = name { | |
3dfed10e XL |
3084 | lifetime_names.insert(name.name); |
3085 | lifetime_spans.push(name.span); | |
dfeec247 XL |
3086 | } |
3087 | } | |
cdc7bbd5 XL |
3088 | match scope_type { |
3089 | BinderScopeType::Normal => late_depth += 1, | |
3090 | BinderScopeType::Concatenating => {} | |
3091 | } | |
dfeec247 XL |
3092 | scope = s; |
3093 | } | |
3094 | ||
3095 | Scope::Elision { ref elide, ref s, .. } => { | |
3096 | let lifetime = match *elide { | |
cdc7bbd5 | 3097 | Elide::FreshLateAnon(named_late_bound_vars, ref counter) => { |
dfeec247 | 3098 | for lifetime_ref in lifetime_refs { |
cdc7bbd5 XL |
3099 | let lifetime = Region::late_anon(named_late_bound_vars, counter) |
3100 | .shifted(late_depth); | |
3101 | ||
dfeec247 XL |
3102 | self.insert_lifetime(lifetime_ref, lifetime); |
3103 | } | |
3104 | return; | |
3105 | } | |
3106 | Elide::Exact(l) => l.shifted(late_depth), | |
3107 | Elide::Error(ref e) => { | |
3dfed10e XL |
3108 | let mut scope = s; |
3109 | loop { | |
3110 | match scope { | |
3111 | Scope::Binder { ref lifetimes, s, .. } => { | |
3112 | // Collect named lifetimes for suggestions. | |
3113 | for name in lifetimes.keys() { | |
3114 | if let hir::ParamName::Plain(name) = name { | |
3115 | lifetime_names.insert(name.name); | |
3116 | lifetime_spans.push(name.span); | |
3117 | } | |
3118 | } | |
3119 | scope = s; | |
3120 | } | |
3121 | Scope::ObjectLifetimeDefault { ref s, .. } | |
cdc7bbd5 XL |
3122 | | Scope::Elision { ref s, .. } |
3123 | | Scope::TraitRefBoundary { ref s, .. } => { | |
3dfed10e | 3124 | scope = s; |
dfeec247 | 3125 | } |
3dfed10e | 3126 | _ => break, |
dfeec247 XL |
3127 | } |
3128 | } | |
5869c6ff | 3129 | break Some(&e[..]); |
dfeec247 | 3130 | } |
f035d41b | 3131 | Elide::Forbid => break None, |
dfeec247 XL |
3132 | }; |
3133 | for lifetime_ref in lifetime_refs { | |
3134 | self.insert_lifetime(lifetime_ref, lifetime); | |
3135 | } | |
3136 | return; | |
3137 | } | |
3138 | ||
cdc7bbd5 XL |
3139 | Scope::ObjectLifetimeDefault { s, .. } |
3140 | | Scope::Supertrait { s, .. } | |
3141 | | Scope::TraitRefBoundary { s, .. } => { | |
dfeec247 XL |
3142 | scope = s; |
3143 | } | |
3144 | } | |
3145 | }; | |
3146 | ||
17df50a5 XL |
3147 | // If we specifically need the `scope_for_path` map, then we're in the |
3148 | // diagnostic pass and we don't want to emit more errors. | |
3149 | if self.map.scope_for_path.is_some() { | |
3150 | self.tcx.sess.delay_span_bug( | |
3151 | rustc_span::DUMMY_SP, | |
3152 | "Encountered unexpected errors during diagnostics related part", | |
3153 | ); | |
3154 | return; | |
3155 | } | |
3156 | ||
3157 | let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect(); | |
3158 | spans.sort(); | |
3159 | let mut spans_dedup = spans.clone(); | |
3160 | spans_dedup.dedup(); | |
3161 | let spans_with_counts: Vec<_> = spans_dedup | |
3162 | .into_iter() | |
3163 | .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count())) | |
3164 | .collect(); | |
3165 | ||
3166 | let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len()); | |
dfeec247 XL |
3167 | |
3168 | if let Some(params) = error { | |
f9f354fc XL |
3169 | // If there's no lifetime available, suggest `'static`. |
3170 | if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() { | |
3dfed10e | 3171 | lifetime_names.insert(kw::StaticLifetime); |
dfeec247 XL |
3172 | } |
3173 | } | |
17df50a5 | 3174 | |
f9f354fc XL |
3175 | self.add_missing_lifetime_specifiers_label( |
3176 | &mut err, | |
17df50a5 | 3177 | spans_with_counts, |
f9f354fc | 3178 | &lifetime_names, |
3dfed10e | 3179 | lifetime_spans, |
5869c6ff | 3180 | error.unwrap_or(&[]), |
f9f354fc | 3181 | ); |
dfeec247 XL |
3182 | err.emit(); |
3183 | } | |
3184 | ||
dfeec247 XL |
3185 | fn report_elision_failure( |
3186 | &mut self, | |
3187 | db: &mut DiagnosticBuilder<'_>, | |
3188 | params: &[ElisionFailureInfo], | |
f9f354fc | 3189 | ) -> bool /* add `'static` lifetime to lifetime list */ { |
dfeec247 XL |
3190 | let mut m = String::new(); |
3191 | let len = params.len(); | |
3192 | ||
3193 | let elided_params: Vec<_> = | |
3194 | params.iter().cloned().filter(|info| info.lifetime_count > 0).collect(); | |
3195 | ||
3196 | let elided_len = elided_params.len(); | |
3197 | ||
3198 | for (i, info) in elided_params.into_iter().enumerate() { | |
74b04a01 XL |
3199 | let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = |
3200 | info; | |
dfeec247 | 3201 | |
74b04a01 | 3202 | db.span_label(span, ""); |
dfeec247 XL |
3203 | let help_name = if let Some(ident) = |
3204 | parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) | |
3205 | { | |
3206 | format!("`{}`", ident) | |
3207 | } else { | |
3208 | format!("argument {}", index + 1) | |
3209 | }; | |
3210 | ||
3211 | m.push_str( | |
3212 | &(if n == 1 { | |
3213 | help_name | |
3214 | } else { | |
3215 | format!( | |
3216 | "one of {}'s {} {}lifetimes", | |
3217 | help_name, | |
3218 | n, | |
3219 | if have_bound_regions { "free " } else { "" } | |
3220 | ) | |
3221 | })[..], | |
3222 | ); | |
3223 | ||
3224 | if elided_len == 2 && i == 0 { | |
3225 | m.push_str(" or "); | |
3226 | } else if i + 2 == elided_len { | |
3227 | m.push_str(", or "); | |
3228 | } else if i != elided_len - 1 { | |
3229 | m.push_str(", "); | |
3230 | } | |
3231 | } | |
3232 | ||
3233 | if len == 0 { | |
3234 | db.help( | |
3235 | "this function's return type contains a borrowed value, \ | |
74b04a01 | 3236 | but there is no value for it to be borrowed from", |
dfeec247 | 3237 | ); |
f9f354fc | 3238 | true |
dfeec247 XL |
3239 | } else if elided_len == 0 { |
3240 | db.help( | |
3241 | "this function's return type contains a borrowed value with \ | |
3242 | an elided lifetime, but the lifetime cannot be derived from \ | |
3243 | the arguments", | |
3244 | ); | |
f9f354fc | 3245 | true |
dfeec247 XL |
3246 | } else if elided_len == 1 { |
3247 | db.help(&format!( | |
3248 | "this function's return type contains a borrowed value, \ | |
74b04a01 | 3249 | but the signature does not say which {} it is borrowed from", |
dfeec247 XL |
3250 | m |
3251 | )); | |
f9f354fc | 3252 | false |
dfeec247 XL |
3253 | } else { |
3254 | db.help(&format!( | |
3255 | "this function's return type contains a borrowed value, \ | |
74b04a01 | 3256 | but the signature does not say whether it is borrowed from {}", |
dfeec247 XL |
3257 | m |
3258 | )); | |
f9f354fc | 3259 | false |
dfeec247 XL |
3260 | } |
3261 | } | |
3262 | ||
3263 | fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { | |
3264 | debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref); | |
3265 | let mut late_depth = 0; | |
3266 | let mut scope = self.scope; | |
3267 | let lifetime = loop { | |
3268 | match *scope { | |
cdc7bbd5 XL |
3269 | Scope::Binder { s, scope_type, .. } => { |
3270 | match scope_type { | |
3271 | BinderScopeType::Normal => late_depth += 1, | |
3272 | BinderScopeType::Concatenating => {} | |
3273 | } | |
dfeec247 XL |
3274 | scope = s; |
3275 | } | |
3276 | ||
3277 | Scope::Root | Scope::Elision { .. } => break Region::Static, | |
3278 | ||
3279 | Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, | |
3280 | ||
3281 | Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, | |
cdc7bbd5 XL |
3282 | |
3283 | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { | |
3284 | scope = s; | |
3285 | } | |
dfeec247 XL |
3286 | } |
3287 | }; | |
3288 | self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); | |
3289 | } | |
3290 | ||
3291 | fn check_lifetime_params( | |
3292 | &mut self, | |
3293 | old_scope: ScopeRef<'_>, | |
3294 | params: &'tcx [hir::GenericParam<'tcx>], | |
3295 | ) { | |
3296 | let lifetimes: Vec<_> = params | |
3297 | .iter() | |
3298 | .filter_map(|param| match param.kind { | |
ba9703b0 XL |
3299 | GenericParamKind::Lifetime { .. } => { |
3300 | Some((param, param.name.normalize_to_macros_2_0())) | |
3301 | } | |
dfeec247 XL |
3302 | _ => None, |
3303 | }) | |
3304 | .collect(); | |
3305 | for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() { | |
3306 | if let hir::ParamName::Plain(_) = lifetime_i_name { | |
3307 | let name = lifetime_i_name.ident().name; | |
3308 | if name == kw::UnderscoreLifetime || name == kw::StaticLifetime { | |
3309 | let mut err = struct_span_err!( | |
3310 | self.tcx.sess, | |
3311 | lifetime_i.span, | |
3312 | E0262, | |
3313 | "invalid lifetime parameter name: `{}`", | |
3314 | lifetime_i.name.ident(), | |
3315 | ); | |
3316 | err.span_label( | |
3317 | lifetime_i.span, | |
3318 | format!("{} is a reserved lifetime name", name), | |
3319 | ); | |
3320 | err.emit(); | |
3321 | } | |
3322 | } | |
3323 | ||
3324 | // It is a hard error to shadow a lifetime within the same scope. | |
3325 | for (lifetime_j, lifetime_j_name) in lifetimes.iter().skip(i + 1) { | |
3326 | if lifetime_i_name == lifetime_j_name { | |
3327 | struct_span_err!( | |
3328 | self.tcx.sess, | |
3329 | lifetime_j.span, | |
3330 | E0263, | |
3331 | "lifetime name `{}` declared twice in the same scope", | |
3332 | lifetime_j.name.ident() | |
3333 | ) | |
3334 | .span_label(lifetime_j.span, "declared twice") | |
3335 | .span_label(lifetime_i.span, "previous declaration here") | |
3336 | .emit(); | |
3337 | } | |
3338 | } | |
3339 | ||
3340 | // It is a soft error to shadow a lifetime within a parent scope. | |
3341 | self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i); | |
3342 | ||
3343 | for bound in lifetime_i.bounds { | |
3344 | match bound { | |
3345 | hir::GenericBound::Outlives(ref lt) => match lt.name { | |
3346 | hir::LifetimeName::Underscore => self.tcx.sess.delay_span_bug( | |
3347 | lt.span, | |
3348 | "use of `'_` in illegal place, but not caught by lowering", | |
3349 | ), | |
3350 | hir::LifetimeName::Static => { | |
3351 | self.insert_lifetime(lt, Region::Static); | |
3352 | self.tcx | |
3353 | .sess | |
3354 | .struct_span_warn( | |
3355 | lifetime_i.span.to(lt.span), | |
3356 | &format!( | |
3357 | "unnecessary lifetime parameter `{}`", | |
3358 | lifetime_i.name.ident(), | |
3359 | ), | |
3360 | ) | |
3361 | .help(&format!( | |
3362 | "you can use the `'static` lifetime directly, in place of `{}`", | |
3363 | lifetime_i.name.ident(), | |
3364 | )) | |
3365 | .emit(); | |
3366 | } | |
3367 | hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => { | |
3368 | self.resolve_lifetime_ref(lt); | |
3369 | } | |
3370 | hir::LifetimeName::ImplicitObjectLifetimeDefault => { | |
3371 | self.tcx.sess.delay_span_bug( | |
3372 | lt.span, | |
3373 | "lowering generated `ImplicitObjectLifetimeDefault` \ | |
3374 | outside of an object type", | |
3375 | ) | |
3376 | } | |
3377 | hir::LifetimeName::Error => { | |
3378 | // No need to do anything, error already reported. | |
3379 | } | |
3380 | }, | |
3381 | _ => bug!(), | |
3382 | } | |
3383 | } | |
3384 | } | |
3385 | } | |
3386 | ||
3387 | fn check_lifetime_param_for_shadowing( | |
3388 | &self, | |
3389 | mut old_scope: ScopeRef<'_>, | |
3390 | param: &'tcx hir::GenericParam<'tcx>, | |
3391 | ) { | |
3392 | for label in &self.labels_in_fn { | |
3393 | // FIXME (#24278): non-hygienic comparison | |
3394 | if param.name.ident().name == label.name { | |
3395 | signal_shadowing_problem( | |
3396 | self.tcx, | |
3397 | label.name, | |
3398 | original_label(label.span), | |
3399 | shadower_lifetime(¶m), | |
3400 | ); | |
3401 | return; | |
3402 | } | |
3403 | } | |
3404 | ||
3405 | loop { | |
3406 | match *old_scope { | |
3407 | Scope::Body { s, .. } | |
3408 | | Scope::Elision { s, .. } | |
cdc7bbd5 XL |
3409 | | Scope::ObjectLifetimeDefault { s, .. } |
3410 | | Scope::Supertrait { s, .. } | |
3411 | | Scope::TraitRefBoundary { s, .. } => { | |
dfeec247 XL |
3412 | old_scope = s; |
3413 | } | |
3414 | ||
3415 | Scope::Root => { | |
3416 | return; | |
3417 | } | |
3418 | ||
3419 | Scope::Binder { ref lifetimes, s, .. } => { | |
ba9703b0 | 3420 | if let Some(&def) = lifetimes.get(¶m.name.normalize_to_macros_2_0()) { |
f9f354fc | 3421 | let hir_id = |
3dfed10e | 3422 | self.tcx.hir().local_def_id_to_hir_id(def.id().unwrap().expect_local()); |
dfeec247 XL |
3423 | |
3424 | signal_shadowing_problem( | |
3425 | self.tcx, | |
3426 | param.name.ident().name, | |
3427 | original_lifetime(self.tcx.hir().span(hir_id)), | |
3428 | shadower_lifetime(¶m), | |
3429 | ); | |
3430 | return; | |
3431 | } | |
3432 | ||
3433 | old_scope = s; | |
3434 | } | |
3435 | } | |
3436 | } | |
3437 | } | |
3438 | ||
3439 | /// Returns `true` if, in the current scope, replacing `'_` would be | |
3440 | /// equivalent to a single-use lifetime. | |
3441 | fn track_lifetime_uses(&self) -> bool { | |
3442 | let mut scope = self.scope; | |
3443 | loop { | |
3444 | match *scope { | |
3445 | Scope::Root => break false, | |
3446 | ||
3447 | // Inside of items, it depends on the kind of item. | |
3448 | Scope::Binder { track_lifetime_uses, .. } => break track_lifetime_uses, | |
3449 | ||
3450 | // Inside a body, `'_` will use an inference variable, | |
3451 | // should be fine. | |
3452 | Scope::Body { .. } => break true, | |
3453 | ||
3454 | // A lifetime only used in a fn argument could as well | |
3455 | // be replaced with `'_`, as that would generate a | |
3456 | // fresh name, too. | |
cdc7bbd5 | 3457 | Scope::Elision { elide: Elide::FreshLateAnon(..), .. } => break true, |
dfeec247 XL |
3458 | |
3459 | // In the return type or other such place, `'_` is not | |
3460 | // going to make a fresh name, so we cannot | |
3461 | // necessarily replace a single-use lifetime with | |
3462 | // `'_`. | |
f035d41b XL |
3463 | Scope::Elision { |
3464 | elide: Elide::Exact(_) | Elide::Error(_) | Elide::Forbid, .. | |
3465 | } => break false, | |
dfeec247 | 3466 | |
cdc7bbd5 XL |
3467 | Scope::ObjectLifetimeDefault { s, .. } |
3468 | | Scope::Supertrait { s, .. } | |
3469 | | Scope::TraitRefBoundary { s, .. } => scope = s, | |
dfeec247 XL |
3470 | } |
3471 | } | |
3472 | } | |
3473 | ||
cdc7bbd5 | 3474 | #[tracing::instrument(level = "debug", skip(self))] |
dfeec247 | 3475 | fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { |
dfeec247 | 3476 | debug!( |
cdc7bbd5 | 3477 | node = ?self.tcx.hir().node_to_string(lifetime_ref.hir_id), |
17df50a5 | 3478 | span = ?self.tcx.sess.source_map().span_to_diagnostic_string(lifetime_ref.span) |
dfeec247 XL |
3479 | ); |
3480 | self.map.defs.insert(lifetime_ref.hir_id, def); | |
3481 | ||
3482 | match def { | |
3483 | Region::LateBoundAnon(..) | Region::Static => { | |
3484 | // These are anonymous lifetimes or lifetimes that are not declared. | |
3485 | } | |
3486 | ||
3487 | Region::Free(_, def_id) | |
cdc7bbd5 | 3488 | | Region::LateBound(_, _, def_id, _) |
dfeec247 XL |
3489 | | Region::EarlyBound(_, def_id, _) => { |
3490 | // A lifetime declared by the user. | |
3491 | let track_lifetime_uses = self.track_lifetime_uses(); | |
cdc7bbd5 | 3492 | debug!(?track_lifetime_uses); |
dfeec247 | 3493 | if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) { |
cdc7bbd5 | 3494 | debug!("first use of {:?}", def_id); |
dfeec247 XL |
3495 | self.lifetime_uses.insert(def_id, LifetimeUseSet::One(lifetime_ref)); |
3496 | } else { | |
cdc7bbd5 | 3497 | debug!("many uses of {:?}", def_id); |
dfeec247 XL |
3498 | self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); |
3499 | } | |
3500 | } | |
3501 | } | |
3502 | } | |
3503 | ||
3504 | /// Sometimes we resolve a lifetime, but later find that it is an | |
3505 | /// error (esp. around impl trait). In that case, we remove the | |
3506 | /// entry into `map.defs` so as not to confuse later code. | |
3507 | fn uninsert_lifetime_on_error(&mut self, lifetime_ref: &'tcx hir::Lifetime, bad_def: Region) { | |
3508 | let old_value = self.map.defs.remove(&lifetime_ref.hir_id); | |
3509 | assert_eq!(old_value, Some(bad_def)); | |
3510 | } | |
3511 | } | |
3512 | ||
3513 | /// Detects late-bound lifetimes and inserts them into | |
3514 | /// `map.late_bound`. | |
3515 | /// | |
3516 | /// A region declared on a fn is **late-bound** if: | |
3517 | /// - it is constrained by an argument type; | |
3518 | /// - it does not appear in a where-clause. | |
3519 | /// | |
3520 | /// "Constrained" basically means that it appears in any type but | |
3521 | /// not amongst the inputs to a projection. In other words, `<&'a | |
3522 | /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. | |
cdc7bbd5 | 3523 | #[tracing::instrument(level = "debug", skip(map))] |
dfeec247 XL |
3524 | fn insert_late_bound_lifetimes( |
3525 | map: &mut NamedRegionMap, | |
3526 | decl: &hir::FnDecl<'_>, | |
3527 | generics: &hir::Generics<'_>, | |
3528 | ) { | |
dfeec247 XL |
3529 | let mut constrained_by_input = ConstrainedCollector::default(); |
3530 | for arg_ty in decl.inputs { | |
3531 | constrained_by_input.visit_ty(arg_ty); | |
3532 | } | |
3533 | ||
3534 | let mut appears_in_output = AllCollector::default(); | |
3535 | intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); | |
3536 | ||
cdc7bbd5 | 3537 | debug!(?constrained_by_input.regions); |
dfeec247 XL |
3538 | |
3539 | // Walk the lifetimes that appear in where clauses. | |
3540 | // | |
3541 | // Subtle point: because we disallow nested bindings, we can just | |
3542 | // ignore binders here and scrape up all names we see. | |
3543 | let mut appears_in_where_clause = AllCollector::default(); | |
3544 | appears_in_where_clause.visit_generics(generics); | |
3545 | ||
3546 | for param in generics.params { | |
3547 | if let hir::GenericParamKind::Lifetime { .. } = param.kind { | |
3548 | if !param.bounds.is_empty() { | |
3549 | // `'a: 'b` means both `'a` and `'b` are referenced | |
3550 | appears_in_where_clause | |
3551 | .regions | |
ba9703b0 | 3552 | .insert(hir::LifetimeName::Param(param.name.normalize_to_macros_2_0())); |
dfeec247 XL |
3553 | } |
3554 | } | |
3555 | } | |
3556 | ||
cdc7bbd5 | 3557 | debug!(?appears_in_where_clause.regions); |
dfeec247 XL |
3558 | |
3559 | // Late bound regions are those that: | |
3560 | // - appear in the inputs | |
3561 | // - do not appear in the where-clauses | |
3562 | // - are not implicitly captured by `impl Trait` | |
3563 | for param in generics.params { | |
3564 | match param.kind { | |
3565 | hir::GenericParamKind::Lifetime { .. } => { /* fall through */ } | |
3566 | ||
3567 | // Neither types nor consts are late-bound. | |
3568 | hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue, | |
3569 | } | |
3570 | ||
ba9703b0 | 3571 | let lt_name = hir::LifetimeName::Param(param.name.normalize_to_macros_2_0()); |
dfeec247 XL |
3572 | // appears in the where clauses? early-bound. |
3573 | if appears_in_where_clause.regions.contains(<_name) { | |
3574 | continue; | |
3575 | } | |
3576 | ||
3577 | // does not appear in the inputs, but appears in the return type? early-bound. | |
3578 | if !constrained_by_input.regions.contains(<_name) | |
3579 | && appears_in_output.regions.contains(<_name) | |
3580 | { | |
3581 | continue; | |
3582 | } | |
3583 | ||
cdc7bbd5 | 3584 | debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id); |
dfeec247 XL |
3585 | |
3586 | let inserted = map.late_bound.insert(param.hir_id); | |
3587 | assert!(inserted, "visited lifetime {:?} twice", param.hir_id); | |
3588 | } | |
3589 | ||
3590 | return; | |
3591 | ||
3592 | #[derive(Default)] | |
3593 | struct ConstrainedCollector { | |
3594 | regions: FxHashSet<hir::LifetimeName>, | |
3595 | } | |
3596 | ||
3597 | impl<'v> Visitor<'v> for ConstrainedCollector { | |
ba9703b0 | 3598 | type Map = intravisit::ErasedMap<'v>; |
dfeec247 | 3599 | |
ba9703b0 | 3600 | fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
dfeec247 XL |
3601 | NestedVisitorMap::None |
3602 | } | |
3603 | ||
3604 | fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { | |
3605 | match ty.kind { | |
ba9703b0 XL |
3606 | hir::TyKind::Path( |
3607 | hir::QPath::Resolved(Some(_), _) | hir::QPath::TypeRelative(..), | |
3608 | ) => { | |
dfeec247 XL |
3609 | // ignore lifetimes appearing in associated type |
3610 | // projections, as they are not *constrained* | |
3611 | // (defined above) | |
3612 | } | |
3613 | ||
3614 | hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { | |
3615 | // consider only the lifetimes on the final | |
3616 | // segment; I am not sure it's even currently | |
3617 | // valid to have them elsewhere, but even if it | |
3618 | // is, those would be potentially inputs to | |
3619 | // projections | |
3620 | if let Some(last_segment) = path.segments.last() { | |
3621 | self.visit_path_segment(path.span, last_segment); | |
3622 | } | |
3623 | } | |
3624 | ||
3625 | _ => { | |
3626 | intravisit::walk_ty(self, ty); | |
3627 | } | |
3628 | } | |
3629 | } | |
3630 | ||
3631 | fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { | |
ba9703b0 | 3632 | self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0()); |
dfeec247 XL |
3633 | } |
3634 | } | |
3635 | ||
3636 | #[derive(Default)] | |
3637 | struct AllCollector { | |
3638 | regions: FxHashSet<hir::LifetimeName>, | |
3639 | } | |
3640 | ||
3641 | impl<'v> Visitor<'v> for AllCollector { | |
ba9703b0 | 3642 | type Map = intravisit::ErasedMap<'v>; |
dfeec247 | 3643 | |
ba9703b0 | 3644 | fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
dfeec247 XL |
3645 | NestedVisitorMap::None |
3646 | } | |
3647 | ||
3648 | fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { | |
ba9703b0 | 3649 | self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0()); |
dfeec247 XL |
3650 | } |
3651 | } | |
3652 | } |