]>
Commit | Line | Data |
---|---|---|
6a06907d | 1 | use crate::ty; |
2b03887a | 2 | use crate::ty::{EarlyBinder, SubstsRef}; |
6a06907d XL |
3 | use rustc_ast as ast; |
4 | use rustc_data_structures::fx::FxHashMap; | |
6a06907d | 5 | use rustc_hir::def_id::DefId; |
487cf647 | 6 | use rustc_span::symbol::{kw, Symbol}; |
6a06907d XL |
7 | use rustc_span::Span; |
8 | ||
9 | use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predicate, TyCtxt}; | |
10 | ||
11 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] | |
12 | pub enum GenericParamDefKind { | |
13 | Lifetime, | |
f2b60f7d | 14 | Type { has_default: bool, synthetic: bool }, |
3c0e092e | 15 | Const { has_default: bool }, |
6a06907d XL |
16 | } |
17 | ||
18 | impl GenericParamDefKind { | |
19 | pub fn descr(&self) -> &'static str { | |
20 | match self { | |
21 | GenericParamDefKind::Lifetime => "lifetime", | |
22 | GenericParamDefKind::Type { .. } => "type", | |
cdc7bbd5 | 23 | GenericParamDefKind::Const { .. } => "constant", |
6a06907d XL |
24 | } |
25 | } | |
a2a8927a | 26 | pub fn to_ord(&self) -> ast::ParamKindOrd { |
6a06907d XL |
27 | match self { |
28 | GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime, | |
f2b60f7d FG |
29 | GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { |
30 | ast::ParamKindOrd::TypeOrConst | |
31 | } | |
6a06907d XL |
32 | } |
33 | } | |
5099ac24 FG |
34 | |
35 | pub fn is_ty_or_const(&self) -> bool { | |
36 | match self { | |
37 | GenericParamDefKind::Lifetime => false, | |
38 | GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => true, | |
39 | } | |
40 | } | |
923072b8 FG |
41 | |
42 | pub fn is_synthetic(&self) -> bool { | |
43 | match self { | |
44 | GenericParamDefKind::Type { synthetic, .. } => *synthetic, | |
45 | _ => false, | |
46 | } | |
47 | } | |
6a06907d XL |
48 | } |
49 | ||
50 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] | |
51 | pub struct GenericParamDef { | |
52 | pub name: Symbol, | |
53 | pub def_id: DefId, | |
54 | pub index: u32, | |
55 | ||
56 | /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute | |
57 | /// on generic parameter `'a`/`T`, asserts data behind the parameter | |
58 | /// `'a`/`T` won't be accessed during the parent type's `Drop` impl. | |
59 | pub pure_wrt_drop: bool, | |
60 | ||
61 | pub kind: GenericParamDefKind, | |
62 | } | |
63 | ||
64 | impl GenericParamDef { | |
65 | pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion { | |
66 | if let GenericParamDefKind::Lifetime = self.kind { | |
67 | ty::EarlyBoundRegion { def_id: self.def_id, index: self.index, name: self.name } | |
68 | } else { | |
69 | bug!("cannot convert a non-lifetime parameter def to an early bound region") | |
70 | } | |
71 | } | |
923072b8 | 72 | |
487cf647 FG |
73 | pub fn is_anonymous_lifetime(&self) -> bool { |
74 | match self.kind { | |
75 | GenericParamDefKind::Lifetime => { | |
76 | self.name == kw::UnderscoreLifetime || self.name == kw::Empty | |
77 | } | |
78 | _ => false, | |
79 | } | |
80 | } | |
81 | ||
923072b8 FG |
82 | pub fn default_value<'tcx>( |
83 | &self, | |
84 | tcx: TyCtxt<'tcx>, | |
85 | ) -> Option<EarlyBinder<ty::GenericArg<'tcx>>> { | |
86 | match self.kind { | |
87 | GenericParamDefKind::Type { has_default, .. } if has_default => { | |
9ffffee4 | 88 | Some(tcx.type_of(self.def_id).map_bound(|t| t.into())) |
923072b8 FG |
89 | } |
90 | GenericParamDefKind::Const { has_default } if has_default => { | |
9c376795 | 91 | Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into())) |
923072b8 FG |
92 | } |
93 | _ => None, | |
94 | } | |
95 | } | |
487cf647 FG |
96 | |
97 | pub fn to_error<'tcx>( | |
98 | &self, | |
99 | tcx: TyCtxt<'tcx>, | |
100 | preceding_substs: &[ty::GenericArg<'tcx>], | |
101 | ) -> ty::GenericArg<'tcx> { | |
102 | match &self.kind { | |
9ffffee4 FG |
103 | ty::GenericParamDefKind::Lifetime => tcx.mk_re_error_misc().into(), |
104 | ty::GenericParamDefKind::Type { .. } => tcx.ty_error_misc().into(), | |
487cf647 | 105 | ty::GenericParamDefKind::Const { .. } => { |
9ffffee4 | 106 | tcx.const_error(tcx.type_of(self.def_id).subst(tcx, preceding_substs)).into() |
487cf647 FG |
107 | } |
108 | } | |
109 | } | |
6a06907d XL |
110 | } |
111 | ||
112 | #[derive(Default)] | |
113 | pub struct GenericParamCount { | |
114 | pub lifetimes: usize, | |
115 | pub types: usize, | |
116 | pub consts: usize, | |
117 | } | |
118 | ||
119 | /// Information about the formal type/lifetime parameters associated | |
120 | /// with an item or method. Analogous to `hir::Generics`. | |
121 | /// | |
122 | /// The ordering of parameters is the same as in `Subst` (excluding child generics): | |
123 | /// `Self` (optionally), `Lifetime` params..., `Type` params... | |
124 | #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] | |
125 | pub struct Generics { | |
126 | pub parent: Option<DefId>, | |
127 | pub parent_count: usize, | |
128 | pub params: Vec<GenericParamDef>, | |
129 | ||
130 | /// Reverse map to the `index` field of each `GenericParamDef`. | |
131 | #[stable_hasher(ignore)] | |
132 | pub param_def_id_to_index: FxHashMap<DefId, u32>, | |
133 | ||
134 | pub has_self: bool, | |
135 | pub has_late_bound_regions: Option<Span>, | |
136 | } | |
137 | ||
138 | impl<'tcx> Generics { | |
f2b60f7d FG |
139 | /// Looks through the generics and all parents to find the index of the |
140 | /// given param def-id. This is in comparison to the `param_def_id_to_index` | |
141 | /// struct member, which only stores information about this item's own | |
142 | /// generics. | |
143 | pub fn param_def_id_to_index(&self, tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<u32> { | |
144 | if let Some(idx) = self.param_def_id_to_index.get(&def_id) { | |
145 | Some(*idx) | |
146 | } else if let Some(parent) = self.parent { | |
147 | let parent = tcx.generics_of(parent); | |
148 | parent.param_def_id_to_index(tcx, def_id) | |
149 | } else { | |
150 | None | |
151 | } | |
152 | } | |
153 | ||
17df50a5 | 154 | #[inline] |
6a06907d XL |
155 | pub fn count(&self) -> usize { |
156 | self.parent_count + self.params.len() | |
157 | } | |
158 | ||
159 | pub fn own_counts(&self) -> GenericParamCount { | |
160 | // We could cache this as a property of `GenericParamCount`, but | |
161 | // the aim is to refactor this away entirely eventually and the | |
162 | // presence of this method will be a constant reminder. | |
163 | let mut own_counts = GenericParamCount::default(); | |
164 | ||
165 | for param in &self.params { | |
166 | match param.kind { | |
167 | GenericParamDefKind::Lifetime => own_counts.lifetimes += 1, | |
168 | GenericParamDefKind::Type { .. } => own_counts.types += 1, | |
cdc7bbd5 | 169 | GenericParamDefKind::Const { .. } => own_counts.consts += 1, |
6a06907d XL |
170 | } |
171 | } | |
172 | ||
173 | own_counts | |
174 | } | |
175 | ||
176 | pub fn own_defaults(&self) -> GenericParamCount { | |
177 | let mut own_defaults = GenericParamCount::default(); | |
178 | ||
179 | for param in &self.params { | |
180 | match param.kind { | |
181 | GenericParamDefKind::Lifetime => (), | |
182 | GenericParamDefKind::Type { has_default, .. } => { | |
183 | own_defaults.types += has_default as usize; | |
184 | } | |
cdc7bbd5 XL |
185 | GenericParamDefKind::Const { has_default } => { |
186 | own_defaults.consts += has_default as usize; | |
6a06907d XL |
187 | } |
188 | } | |
189 | } | |
190 | ||
191 | own_defaults | |
192 | } | |
193 | ||
194 | pub fn requires_monomorphization(&self, tcx: TyCtxt<'tcx>) -> bool { | |
195 | if self.own_requires_monomorphization() { | |
196 | return true; | |
197 | } | |
198 | ||
199 | if let Some(parent_def_id) = self.parent { | |
200 | let parent = tcx.generics_of(parent_def_id); | |
201 | parent.requires_monomorphization(tcx) | |
202 | } else { | |
203 | false | |
204 | } | |
205 | } | |
206 | ||
207 | pub fn own_requires_monomorphization(&self) -> bool { | |
208 | for param in &self.params { | |
209 | match param.kind { | |
cdc7bbd5 XL |
210 | GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { |
211 | return true; | |
212 | } | |
6a06907d XL |
213 | GenericParamDefKind::Lifetime => {} |
214 | } | |
215 | } | |
216 | false | |
217 | } | |
218 | ||
219 | /// Returns the `GenericParamDef` with the given index. | |
220 | pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef { | |
221 | if let Some(index) = param_index.checked_sub(self.parent_count) { | |
222 | &self.params[index] | |
223 | } else { | |
224 | tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?")) | |
225 | .param_at(param_index, tcx) | |
226 | } | |
227 | } | |
228 | ||
9c376795 FG |
229 | pub fn params_to(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx [GenericParamDef] { |
230 | if let Some(index) = param_index.checked_sub(self.parent_count) { | |
231 | &self.params[..index] | |
232 | } else { | |
233 | tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?")) | |
234 | .params_to(param_index, tcx) | |
235 | } | |
236 | } | |
237 | ||
6a06907d XL |
238 | /// Returns the `GenericParamDef` associated with this `EarlyBoundRegion`. |
239 | pub fn region_param( | |
240 | &'tcx self, | |
241 | param: &EarlyBoundRegion, | |
242 | tcx: TyCtxt<'tcx>, | |
243 | ) -> &'tcx GenericParamDef { | |
244 | let param = self.param_at(param.index as usize, tcx); | |
245 | match param.kind { | |
246 | GenericParamDefKind::Lifetime => param, | |
247 | _ => bug!("expected lifetime parameter, but found another generic parameter"), | |
248 | } | |
249 | } | |
250 | ||
251 | /// Returns the `GenericParamDef` associated with this `ParamTy`. | |
252 | pub fn type_param(&'tcx self, param: &ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef { | |
253 | let param = self.param_at(param.index as usize, tcx); | |
254 | match param.kind { | |
255 | GenericParamDefKind::Type { .. } => param, | |
256 | _ => bug!("expected type parameter, but found another generic parameter"), | |
257 | } | |
258 | } | |
259 | ||
260 | /// Returns the `GenericParamDef` associated with this `ParamConst`. | |
261 | pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef { | |
262 | let param = self.param_at(param.index as usize, tcx); | |
263 | match param.kind { | |
cdc7bbd5 | 264 | GenericParamDefKind::Const { .. } => param, |
6a06907d XL |
265 | _ => bug!("expected const parameter, but found another generic parameter"), |
266 | } | |
267 | } | |
94222f64 XL |
268 | |
269 | /// Returns `true` if `params` has `impl Trait`. | |
270 | pub fn has_impl_trait(&'tcx self) -> bool { | |
271 | self.params.iter().any(|param| { | |
3c0e092e | 272 | matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. }) |
94222f64 XL |
273 | }) |
274 | } | |
923072b8 FG |
275 | |
276 | /// Returns the substs corresponding to the generic parameters | |
277 | /// of this item, excluding `Self`. | |
278 | /// | |
279 | /// **This should only be used for diagnostics purposes.** | |
280 | pub fn own_substs_no_defaults( | |
281 | &'tcx self, | |
282 | tcx: TyCtxt<'tcx>, | |
283 | substs: &'tcx [ty::GenericArg<'tcx>], | |
284 | ) -> &'tcx [ty::GenericArg<'tcx>] { | |
285 | let mut own_params = self.parent_count..self.count(); | |
286 | if self.has_self && self.parent.is_none() { | |
287 | own_params.start = 1; | |
288 | } | |
289 | ||
290 | // Filter the default arguments. | |
291 | // | |
292 | // This currently uses structural equality instead | |
f2b60f7d | 293 | // of semantic equivalence. While not ideal, that's |
923072b8 FG |
294 | // good enough for now as this should only be used |
295 | // for diagnostics anyways. | |
296 | own_params.end -= self | |
297 | .params | |
298 | .iter() | |
299 | .rev() | |
300 | .take_while(|param| { | |
301 | param.default_value(tcx).map_or(false, |default| { | |
302 | default.subst(tcx, substs) == substs[param.index as usize] | |
303 | }) | |
304 | }) | |
305 | .count(); | |
306 | ||
307 | &substs[own_params] | |
308 | } | |
309 | ||
310 | /// Returns the substs corresponding to the generic parameters of this item, excluding `Self`. | |
311 | /// | |
312 | /// **This should only be used for diagnostics purposes.** | |
313 | pub fn own_substs( | |
314 | &'tcx self, | |
315 | substs: &'tcx [ty::GenericArg<'tcx>], | |
316 | ) -> &'tcx [ty::GenericArg<'tcx>] { | |
317 | let own = &substs[self.parent_count..][..self.params.len()]; | |
318 | if self.has_self && self.parent.is_none() { &own[1..] } else { &own } | |
319 | } | |
6a06907d XL |
320 | } |
321 | ||
322 | /// Bounds on generics. | |
323 | #[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)] | |
324 | pub struct GenericPredicates<'tcx> { | |
325 | pub parent: Option<DefId>, | |
326 | pub predicates: &'tcx [(Predicate<'tcx>, Span)], | |
327 | } | |
328 | ||
329 | impl<'tcx> GenericPredicates<'tcx> { | |
330 | pub fn instantiate( | |
331 | &self, | |
332 | tcx: TyCtxt<'tcx>, | |
333 | substs: SubstsRef<'tcx>, | |
334 | ) -> InstantiatedPredicates<'tcx> { | |
335 | let mut instantiated = InstantiatedPredicates::empty(); | |
336 | self.instantiate_into(tcx, &mut instantiated, substs); | |
337 | instantiated | |
338 | } | |
339 | ||
340 | pub fn instantiate_own( | |
341 | &self, | |
342 | tcx: TyCtxt<'tcx>, | |
343 | substs: SubstsRef<'tcx>, | |
9c376795 FG |
344 | ) -> impl Iterator<Item = (Predicate<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator |
345 | { | |
346 | EarlyBinder(self.predicates).subst_iter_copied(tcx, substs) | |
6a06907d XL |
347 | } |
348 | ||
f2b60f7d | 349 | #[instrument(level = "debug", skip(self, tcx))] |
6a06907d XL |
350 | fn instantiate_into( |
351 | &self, | |
352 | tcx: TyCtxt<'tcx>, | |
353 | instantiated: &mut InstantiatedPredicates<'tcx>, | |
354 | substs: SubstsRef<'tcx>, | |
355 | ) { | |
356 | if let Some(def_id) = self.parent { | |
357 | tcx.predicates_of(def_id).instantiate_into(tcx, instantiated, substs); | |
358 | } | |
04454e1e FG |
359 | instantiated |
360 | .predicates | |
361 | .extend(self.predicates.iter().map(|(p, _)| EarlyBinder(*p).subst(tcx, substs))); | |
6a06907d XL |
362 | instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp)); |
363 | } | |
364 | ||
365 | pub fn instantiate_identity(&self, tcx: TyCtxt<'tcx>) -> InstantiatedPredicates<'tcx> { | |
366 | let mut instantiated = InstantiatedPredicates::empty(); | |
367 | self.instantiate_identity_into(tcx, &mut instantiated); | |
368 | instantiated | |
369 | } | |
370 | ||
371 | fn instantiate_identity_into( | |
372 | &self, | |
373 | tcx: TyCtxt<'tcx>, | |
374 | instantiated: &mut InstantiatedPredicates<'tcx>, | |
375 | ) { | |
376 | if let Some(def_id) = self.parent { | |
377 | tcx.predicates_of(def_id).instantiate_identity_into(tcx, instantiated); | |
378 | } | |
379 | instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p)); | |
380 | instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s)); | |
381 | } | |
382 | } |