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