1 use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
2 use crate::ty;
3 use crate::ty::subst::{Subst, SubstsRef};
4 use rustc_ast as ast;
5 use rustc_data_structures::fx::FxHashMap;
6 use rustc_hir::def_id::DefId;
7 use rustc_span::symbol::Symbol;
8 use rustc_span::Span;
9 
10 use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predicate, TyCtxt};
11 
12 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
13 pub enum GenericParamDefKind {
14     Lifetime,
15     Type { has_default: bool, object_lifetime_default: ObjectLifetimeDefault, synthetic: bool },
16     Const { has_default: bool },
17 }
18 
19 impl GenericParamDefKind {
descr(&self) -> &'static str20     pub fn descr(&self) -> &'static str {
21         match self {
22             GenericParamDefKind::Lifetime => "lifetime",
23             GenericParamDefKind::Type { .. } => "type",
24             GenericParamDefKind::Const { .. } => "constant",
25         }
26     }
to_ord(&self, tcx: TyCtxt<'_>) -> ast::ParamKindOrd27     pub fn to_ord(&self, tcx: TyCtxt<'_>) -> ast::ParamKindOrd {
28         match self {
29             GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime,
30             GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type,
31             GenericParamDefKind::Const { .. } => {
32                 ast::ParamKindOrd::Const { unordered: tcx.features().unordered_const_ty_params() }
33             }
34         }
35     }
36 }
37 
38 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
39 pub struct GenericParamDef {
40     pub name: Symbol,
41     pub def_id: DefId,
42     pub index: u32,
43 
44     /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
45     /// on generic parameter `'a`/`T`, asserts data behind the parameter
46     /// `'a`/`T` won't be accessed during the parent type's `Drop` impl.
47     pub pure_wrt_drop: bool,
48 
49     pub kind: GenericParamDefKind,
50 }
51 
52 impl GenericParamDef {
to_early_bound_region_data(&self) -> ty::EarlyBoundRegion53     pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion {
54         if let GenericParamDefKind::Lifetime = self.kind {
55             ty::EarlyBoundRegion { def_id: self.def_id, index: self.index, name: self.name }
56         } else {
57             bug!("cannot convert a non-lifetime parameter def to an early bound region")
58         }
59     }
60 }
61 
62 #[derive(Default)]
63 pub struct GenericParamCount {
64     pub lifetimes: usize,
65     pub types: usize,
66     pub consts: usize,
67 }
68 
69 /// Information about the formal type/lifetime parameters associated
70 /// with an item or method. Analogous to `hir::Generics`.
71 ///
72 /// The ordering of parameters is the same as in `Subst` (excluding child generics):
73 /// `Self` (optionally), `Lifetime` params..., `Type` params...
74 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
75 pub struct Generics {
76     pub parent: Option<DefId>,
77     pub parent_count: usize,
78     pub params: Vec<GenericParamDef>,
79 
80     /// Reverse map to the `index` field of each `GenericParamDef`.
81     #[stable_hasher(ignore)]
82     pub param_def_id_to_index: FxHashMap<DefId, u32>,
83 
84     pub has_self: bool,
85     pub has_late_bound_regions: Option<Span>,
86 }
87 
88 impl<'tcx> Generics {
89     #[inline]
count(&self) -> usize90     pub fn count(&self) -> usize {
91         self.parent_count + self.params.len()
92     }
93 
own_counts(&self) -> GenericParamCount94     pub fn own_counts(&self) -> GenericParamCount {
95         // We could cache this as a property of `GenericParamCount`, but
96         // the aim is to refactor this away entirely eventually and the
97         // presence of this method will be a constant reminder.
98         let mut own_counts = GenericParamCount::default();
99 
100         for param in &self.params {
101             match param.kind {
102                 GenericParamDefKind::Lifetime => own_counts.lifetimes += 1,
103                 GenericParamDefKind::Type { .. } => own_counts.types += 1,
104                 GenericParamDefKind::Const { .. } => own_counts.consts += 1,
105             }
106         }
107 
108         own_counts
109     }
110 
own_defaults(&self) -> GenericParamCount111     pub fn own_defaults(&self) -> GenericParamCount {
112         let mut own_defaults = GenericParamCount::default();
113 
114         for param in &self.params {
115             match param.kind {
116                 GenericParamDefKind::Lifetime => (),
117                 GenericParamDefKind::Type { has_default, .. } => {
118                     own_defaults.types += has_default as usize;
119                 }
120                 GenericParamDefKind::Const { has_default } => {
121                     own_defaults.consts += has_default as usize;
122                 }
123             }
124         }
125 
126         own_defaults
127     }
128 
requires_monomorphization(&self, tcx: TyCtxt<'tcx>) -> bool129     pub fn requires_monomorphization(&self, tcx: TyCtxt<'tcx>) -> bool {
130         if self.own_requires_monomorphization() {
131             return true;
132         }
133 
134         if let Some(parent_def_id) = self.parent {
135             let parent = tcx.generics_of(parent_def_id);
136             parent.requires_monomorphization(tcx)
137         } else {
138             false
139         }
140     }
141 
own_requires_monomorphization(&self) -> bool142     pub fn own_requires_monomorphization(&self) -> bool {
143         for param in &self.params {
144             match param.kind {
145                 GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
146                     return true;
147                 }
148                 GenericParamDefKind::Lifetime => {}
149             }
150         }
151         false
152     }
153 
154     /// Returns the `GenericParamDef` with the given index.
param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef155     pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
156         if let Some(index) = param_index.checked_sub(self.parent_count) {
157             &self.params[index]
158         } else {
159             tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
160                 .param_at(param_index, tcx)
161         }
162     }
163 
164     /// Returns the `GenericParamDef` associated with this `EarlyBoundRegion`.
region_param( &'tcx self, param: &EarlyBoundRegion, tcx: TyCtxt<'tcx>, ) -> &'tcx GenericParamDef165     pub fn region_param(
166         &'tcx self,
167         param: &EarlyBoundRegion,
168         tcx: TyCtxt<'tcx>,
169     ) -> &'tcx GenericParamDef {
170         let param = self.param_at(param.index as usize, tcx);
171         match param.kind {
172             GenericParamDefKind::Lifetime => param,
173             _ => bug!("expected lifetime parameter, but found another generic parameter"),
174         }
175     }
176 
177     /// Returns the `GenericParamDef` associated with this `ParamTy`.
type_param(&'tcx self, param: &ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef178     pub fn type_param(&'tcx self, param: &ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
179         let param = self.param_at(param.index as usize, tcx);
180         match param.kind {
181             GenericParamDefKind::Type { .. } => param,
182             _ => bug!("expected type parameter, but found another generic parameter"),
183         }
184     }
185 
186     /// Returns the `GenericParamDef` associated with this `ParamConst`.
const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef187     pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef {
188         let param = self.param_at(param.index as usize, tcx);
189         match param.kind {
190             GenericParamDefKind::Const { .. } => param,
191             _ => bug!("expected const parameter, but found another generic parameter"),
192         }
193     }
194 
195     /// Returns `true` if `params` has `impl Trait`.
has_impl_trait(&'tcx self) -> bool196     pub fn has_impl_trait(&'tcx self) -> bool {
197         self.params.iter().any(|param| {
198             matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
199         })
200     }
201 }
202 
203 /// Bounds on generics.
204 #[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)]
205 pub struct GenericPredicates<'tcx> {
206     pub parent: Option<DefId>,
207     pub predicates: &'tcx [(Predicate<'tcx>, Span)],
208 }
209 
210 impl<'tcx> GenericPredicates<'tcx> {
instantiate( &self, tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, ) -> InstantiatedPredicates<'tcx>211     pub fn instantiate(
212         &self,
213         tcx: TyCtxt<'tcx>,
214         substs: SubstsRef<'tcx>,
215     ) -> InstantiatedPredicates<'tcx> {
216         let mut instantiated = InstantiatedPredicates::empty();
217         self.instantiate_into(tcx, &mut instantiated, substs);
218         instantiated
219     }
220 
instantiate_own( &self, tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, ) -> InstantiatedPredicates<'tcx>221     pub fn instantiate_own(
222         &self,
223         tcx: TyCtxt<'tcx>,
224         substs: SubstsRef<'tcx>,
225     ) -> InstantiatedPredicates<'tcx> {
226         InstantiatedPredicates {
227             predicates: self.predicates.iter().map(|(p, _)| p.subst(tcx, substs)).collect(),
228             spans: self.predicates.iter().map(|(_, sp)| *sp).collect(),
229         }
230     }
231 
instantiate_into( &self, tcx: TyCtxt<'tcx>, instantiated: &mut InstantiatedPredicates<'tcx>, substs: SubstsRef<'tcx>, )232     fn instantiate_into(
233         &self,
234         tcx: TyCtxt<'tcx>,
235         instantiated: &mut InstantiatedPredicates<'tcx>,
236         substs: SubstsRef<'tcx>,
237     ) {
238         if let Some(def_id) = self.parent {
239             tcx.predicates_of(def_id).instantiate_into(tcx, instantiated, substs);
240         }
241         instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p.subst(tcx, substs)));
242         instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp));
243     }
244 
instantiate_identity(&self, tcx: TyCtxt<'tcx>) -> InstantiatedPredicates<'tcx>245     pub fn instantiate_identity(&self, tcx: TyCtxt<'tcx>) -> InstantiatedPredicates<'tcx> {
246         let mut instantiated = InstantiatedPredicates::empty();
247         self.instantiate_identity_into(tcx, &mut instantiated);
248         instantiated
249     }
250 
instantiate_identity_into( &self, tcx: TyCtxt<'tcx>, instantiated: &mut InstantiatedPredicates<'tcx>, )251     fn instantiate_identity_into(
252         &self,
253         tcx: TyCtxt<'tcx>,
254         instantiated: &mut InstantiatedPredicates<'tcx>,
255     ) {
256         if let Some(def_id) = self.parent {
257             tcx.predicates_of(def_id).instantiate_identity_into(tcx, instantiated);
258         }
259         instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p));
260         instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s));
261     }
262 }
263