rustc_middle/ty/
generics.rs

1use rustc_ast as ast;
2use rustc_data_structures::fx::FxHashMap;
3use rustc_hir::def_id::DefId;
4use rustc_macros::{HashStable, TyDecodable, TyEncodable};
5use rustc_span::{Span, Symbol, kw};
6use tracing::instrument;
7
8use super::{Clause, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt};
9use crate::ty;
10use crate::ty::{EarlyBinder, GenericArgsRef};
11
12#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
13pub enum GenericParamDefKind {
14    Lifetime,
15    Type { has_default: bool, synthetic: bool },
16    Const { has_default: bool, synthetic: bool },
17}
18
19impl GenericParamDefKind {
20    pub fn descr(&self) -> &'static str {
21        match self {
22            GenericParamDefKind::Lifetime => "lifetime",
23            GenericParamDefKind::Type { .. } => "type",
24            GenericParamDefKind::Const { .. } => "constant",
25        }
26    }
27    pub fn to_ord(&self) -> ast::ParamKindOrd {
28        match self {
29            GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime,
30            GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
31                ast::ParamKindOrd::TypeOrConst
32            }
33        }
34    }
35
36    pub fn is_ty_or_const(&self) -> bool {
37        match self {
38            GenericParamDefKind::Lifetime => false,
39            GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => true,
40        }
41    }
42
43    pub fn is_synthetic(&self) -> bool {
44        match self {
45            GenericParamDefKind::Type { synthetic, .. } => *synthetic,
46            _ => false,
47        }
48    }
49}
50
51#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
52pub struct GenericParamDef {
53    pub name: Symbol,
54    pub def_id: DefId,
55    pub index: u32,
56
57    /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
58    /// on generic parameter `'a`/`T`, asserts data behind the parameter
59    /// `'a`/`T` won't be accessed during the parent type's `Drop` impl.
60    pub pure_wrt_drop: bool,
61
62    pub kind: GenericParamDefKind,
63}
64
65impl GenericParamDef {
66    pub fn to_early_bound_region_data(&self) -> ty::EarlyParamRegion {
67        if let GenericParamDefKind::Lifetime = self.kind {
68            ty::EarlyParamRegion { index: self.index, name: self.name }
69        } else {
70            bug!("cannot convert a non-lifetime parameter def to an early bound region")
71        }
72    }
73
74    pub fn is_anonymous_lifetime(&self) -> bool {
75        match self.kind {
76            GenericParamDefKind::Lifetime => {
77                self.name == kw::UnderscoreLifetime || self.name == kw::Empty
78            }
79            _ => false,
80        }
81    }
82
83    pub fn default_value<'tcx>(
84        &self,
85        tcx: TyCtxt<'tcx>,
86    ) -> Option<EarlyBinder<'tcx, ty::GenericArg<'tcx>>> {
87        match self.kind {
88            GenericParamDefKind::Type { has_default: true, .. } => {
89                Some(tcx.type_of(self.def_id).map_bound(|t| t.into()))
90            }
91            GenericParamDefKind::Const { has_default: true, .. } => {
92                Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
93            }
94            _ => None,
95        }
96    }
97
98    pub fn to_error<'tcx>(&self, tcx: TyCtxt<'tcx>) -> ty::GenericArg<'tcx> {
99        match &self.kind {
100            ty::GenericParamDefKind::Lifetime => ty::Region::new_error_misc(tcx).into(),
101            ty::GenericParamDefKind::Type { .. } => Ty::new_misc_error(tcx).into(),
102            ty::GenericParamDefKind::Const { .. } => ty::Const::new_misc_error(tcx).into(),
103        }
104    }
105}
106
107#[derive(Default)]
108pub struct GenericParamCount {
109    pub lifetimes: usize,
110    pub types: usize,
111    pub consts: usize,
112}
113
114/// Information about the formal type/lifetime parameters associated
115/// with an item or method. Analogous to `hir::Generics`.
116///
117/// The ordering of parameters is the same as in [`ty::GenericArg`] (excluding child generics):
118/// `Self` (optionally), `Lifetime` params..., `Type` params...
119#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
120pub struct Generics {
121    pub parent: Option<DefId>,
122    pub parent_count: usize,
123    pub own_params: Vec<GenericParamDef>,
124
125    /// Reverse map to the `index` field of each `GenericParamDef`.
126    #[stable_hasher(ignore)]
127    pub param_def_id_to_index: FxHashMap<DefId, u32>,
128
129    pub has_self: bool,
130    pub has_late_bound_regions: Option<Span>,
131}
132
133impl<'tcx> rustc_type_ir::inherent::GenericsOf<TyCtxt<'tcx>> for &'tcx Generics {
134    fn count(&self) -> usize {
135        self.parent_count + self.own_params.len()
136    }
137}
138
139impl<'tcx> Generics {
140    /// Looks through the generics and all parents to find the index of the
141    /// given param def-id. This is in comparison to the `param_def_id_to_index`
142    /// struct member, which only stores information about this item's own
143    /// generics.
144    pub fn param_def_id_to_index(&self, tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<u32> {
145        if let Some(idx) = self.param_def_id_to_index.get(&def_id) {
146            Some(*idx)
147        } else if let Some(parent) = self.parent {
148            let parent = tcx.generics_of(parent);
149            parent.param_def_id_to_index(tcx, def_id)
150        } else {
151            None
152        }
153    }
154
155    #[inline]
156    pub fn count(&self) -> usize {
157        self.parent_count + self.own_params.len()
158    }
159
160    pub fn own_counts(&self) -> GenericParamCount {
161        // We could cache this as a property of `GenericParamCount`, but
162        // the aim is to refactor this away entirely eventually and the
163        // presence of this method will be a constant reminder.
164        let mut own_counts = GenericParamCount::default();
165
166        for param in &self.own_params {
167            match param.kind {
168                GenericParamDefKind::Lifetime => own_counts.lifetimes += 1,
169                GenericParamDefKind::Type { .. } => own_counts.types += 1,
170                GenericParamDefKind::Const { .. } => own_counts.consts += 1,
171            }
172        }
173
174        own_counts
175    }
176
177    pub fn own_defaults(&self) -> GenericParamCount {
178        let mut own_defaults = GenericParamCount::default();
179
180        for param in &self.own_params {
181            match param.kind {
182                GenericParamDefKind::Lifetime => (),
183                GenericParamDefKind::Type { has_default, .. } => {
184                    own_defaults.types += has_default as usize;
185                }
186                GenericParamDefKind::Const { has_default, .. } => {
187                    own_defaults.consts += has_default as usize;
188                }
189            }
190        }
191
192        own_defaults
193    }
194
195    pub fn requires_monomorphization(&self, tcx: TyCtxt<'tcx>) -> bool {
196        if self.own_requires_monomorphization() {
197            return true;
198        }
199
200        if let Some(parent_def_id) = self.parent {
201            let parent = tcx.generics_of(parent_def_id);
202            parent.requires_monomorphization(tcx)
203        } else {
204            false
205        }
206    }
207
208    pub fn own_requires_monomorphization(&self) -> bool {
209        for param in &self.own_params {
210            match param.kind {
211                GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
212                    return true;
213                }
214                GenericParamDefKind::Lifetime => {}
215            }
216        }
217        false
218    }
219
220    /// Returns the `GenericParamDef` with the given index.
221    pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
222        if let Some(index) = param_index.checked_sub(self.parent_count) {
223            &self.own_params[index]
224        } else {
225            tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
226                .param_at(param_index, tcx)
227        }
228    }
229
230    pub fn params_to(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx [GenericParamDef] {
231        if let Some(index) = param_index.checked_sub(self.parent_count) {
232            &self.own_params[..index]
233        } else {
234            tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
235                .params_to(param_index, tcx)
236        }
237    }
238
239    /// Returns the `GenericParamDef` associated with this `EarlyParamRegion`.
240    pub fn region_param(
241        &'tcx self,
242        param: ty::EarlyParamRegion,
243        tcx: TyCtxt<'tcx>,
244    ) -> &'tcx GenericParamDef {
245        let param = self.param_at(param.index as usize, tcx);
246        match param.kind {
247            GenericParamDefKind::Lifetime => param,
248            _ => {
249                bug!("expected lifetime parameter, but found another generic parameter: {param:#?}")
250            }
251        }
252    }
253
254    /// Returns the `GenericParamDef` associated with this `ParamTy`.
255    pub fn type_param(&'tcx self, param: ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
256        let param = self.param_at(param.index as usize, tcx);
257        match param.kind {
258            GenericParamDefKind::Type { .. } => param,
259            _ => bug!("expected type parameter, but found another generic parameter: {param:#?}"),
260        }
261    }
262
263    /// Returns the `GenericParamDef` associated with this `ParamConst`.
264    pub fn const_param(&'tcx self, param: ParamConst, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
265        let param = self.param_at(param.index as usize, tcx);
266        match param.kind {
267            GenericParamDefKind::Const { .. } => param,
268            _ => bug!("expected const parameter, but found another generic parameter: {param:#?}"),
269        }
270    }
271
272    /// Returns `true` if `params` has `impl Trait`.
273    pub fn has_impl_trait(&'tcx self) -> bool {
274        self.own_params.iter().any(|param| {
275            matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
276        })
277    }
278
279    /// Returns the args corresponding to the generic parameters
280    /// of this item, excluding `Self`.
281    ///
282    /// **This should only be used for diagnostics purposes.**
283    pub fn own_args_no_defaults<'a>(
284        &'tcx self,
285        tcx: TyCtxt<'tcx>,
286        args: &'a [ty::GenericArg<'tcx>],
287    ) -> &'a [ty::GenericArg<'tcx>] {
288        let mut own_params = self.parent_count..self.count();
289        if self.has_self && self.parent.is_none() {
290            own_params.start = 1;
291        }
292
293        // Filter the default arguments.
294        //
295        // This currently uses structural equality instead
296        // of semantic equivalence. While not ideal, that's
297        // good enough for now as this should only be used
298        // for diagnostics anyways.
299        own_params.end -= self
300            .own_params
301            .iter()
302            .rev()
303            .take_while(|param| {
304                param.default_value(tcx).is_some_and(|default| {
305                    default.instantiate(tcx, args) == args[param.index as usize]
306                })
307            })
308            .count();
309
310        &args[own_params]
311    }
312
313    /// Returns the args corresponding to the generic parameters of this item, excluding `Self`.
314    ///
315    /// **This should only be used for diagnostics purposes.**
316    pub fn own_args(
317        &'tcx self,
318        args: &'tcx [ty::GenericArg<'tcx>],
319    ) -> &'tcx [ty::GenericArg<'tcx>] {
320        let own = &args[self.parent_count..][..self.own_params.len()];
321        if self.has_self && self.parent.is_none() { &own[1..] } else { own }
322    }
323
324    /// Returns true if a concrete type is specified after a default type.
325    /// For example, consider `struct T<W = usize, X = Vec<W>>(W, X)`
326    /// `T<usize, String>` will return true
327    /// `T<usize>` will return false
328    pub fn check_concrete_type_after_default(
329        &'tcx self,
330        tcx: TyCtxt<'tcx>,
331        args: &'tcx [ty::GenericArg<'tcx>],
332    ) -> bool {
333        let mut default_param_seen = false;
334        for param in self.own_params.iter() {
335            if let Some(inst) =
336                param.default_value(tcx).map(|default| default.instantiate(tcx, args))
337            {
338                if inst == args[param.index as usize] {
339                    default_param_seen = true;
340                } else if default_param_seen {
341                    return true;
342                }
343            }
344        }
345        false
346    }
347
348    pub fn is_empty(&'tcx self) -> bool {
349        self.count() == 0
350    }
351
352    pub fn is_own_empty(&'tcx self) -> bool {
353        self.own_params.is_empty()
354    }
355}
356
357/// Bounds on generics.
358#[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)]
359pub struct GenericPredicates<'tcx> {
360    pub parent: Option<DefId>,
361    pub predicates: &'tcx [(Clause<'tcx>, Span)],
362}
363
364impl<'tcx> GenericPredicates<'tcx> {
365    pub fn instantiate(
366        self,
367        tcx: TyCtxt<'tcx>,
368        args: GenericArgsRef<'tcx>,
369    ) -> InstantiatedPredicates<'tcx> {
370        let mut instantiated = InstantiatedPredicates::empty();
371        self.instantiate_into(tcx, &mut instantiated, args);
372        instantiated
373    }
374
375    pub fn instantiate_own(
376        self,
377        tcx: TyCtxt<'tcx>,
378        args: GenericArgsRef<'tcx>,
379    ) -> impl Iterator<Item = (Clause<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator {
380        EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args)
381    }
382
383    pub fn instantiate_own_identity(
384        self,
385    ) -> impl Iterator<Item = (Clause<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator {
386        EarlyBinder::bind(self.predicates).iter_identity_copied()
387    }
388
389    #[instrument(level = "debug", skip(self, tcx))]
390    fn instantiate_into(
391        self,
392        tcx: TyCtxt<'tcx>,
393        instantiated: &mut InstantiatedPredicates<'tcx>,
394        args: GenericArgsRef<'tcx>,
395    ) {
396        if let Some(def_id) = self.parent {
397            tcx.predicates_of(def_id).instantiate_into(tcx, instantiated, args);
398        }
399        instantiated.predicates.extend(
400            self.predicates.iter().map(|(p, _)| EarlyBinder::bind(*p).instantiate(tcx, args)),
401        );
402        instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp));
403    }
404
405    pub fn instantiate_identity(self, tcx: TyCtxt<'tcx>) -> InstantiatedPredicates<'tcx> {
406        let mut instantiated = InstantiatedPredicates::empty();
407        self.instantiate_identity_into(tcx, &mut instantiated);
408        instantiated
409    }
410
411    fn instantiate_identity_into(
412        self,
413        tcx: TyCtxt<'tcx>,
414        instantiated: &mut InstantiatedPredicates<'tcx>,
415    ) {
416        if let Some(def_id) = self.parent {
417            tcx.predicates_of(def_id).instantiate_identity_into(tcx, instantiated);
418        }
419        instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p));
420        instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s));
421    }
422}
423
424/// `~const` bounds for a given item. This is represented using a struct much like
425/// `GenericPredicates`, where you can either choose to only instantiate the "own"
426/// bounds or all of the bounds including those from the parent. This distinction
427/// is necessary for code like `compare_method_predicate_entailment`.
428#[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)]
429pub struct ConstConditions<'tcx> {
430    pub parent: Option<DefId>,
431    pub predicates: &'tcx [(ty::PolyTraitRef<'tcx>, Span)],
432}
433
434impl<'tcx> ConstConditions<'tcx> {
435    pub fn instantiate(
436        self,
437        tcx: TyCtxt<'tcx>,
438        args: GenericArgsRef<'tcx>,
439    ) -> Vec<(ty::PolyTraitRef<'tcx>, Span)> {
440        let mut instantiated = vec![];
441        self.instantiate_into(tcx, &mut instantiated, args);
442        instantiated
443    }
444
445    pub fn instantiate_own(
446        self,
447        tcx: TyCtxt<'tcx>,
448        args: GenericArgsRef<'tcx>,
449    ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
450    {
451        EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args)
452    }
453
454    pub fn instantiate_own_identity(
455        self,
456    ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
457    {
458        EarlyBinder::bind(self.predicates).iter_identity_copied()
459    }
460
461    #[instrument(level = "debug", skip(self, tcx))]
462    fn instantiate_into(
463        self,
464        tcx: TyCtxt<'tcx>,
465        instantiated: &mut Vec<(ty::PolyTraitRef<'tcx>, Span)>,
466        args: GenericArgsRef<'tcx>,
467    ) {
468        if let Some(def_id) = self.parent {
469            tcx.const_conditions(def_id).instantiate_into(tcx, instantiated, args);
470        }
471        instantiated.extend(
472            self.predicates.iter().map(|&(p, s)| (EarlyBinder::bind(p).instantiate(tcx, args), s)),
473        );
474    }
475
476    pub fn instantiate_identity(self, tcx: TyCtxt<'tcx>) -> Vec<(ty::PolyTraitRef<'tcx>, Span)> {
477        let mut instantiated = vec![];
478        self.instantiate_identity_into(tcx, &mut instantiated);
479        instantiated
480    }
481
482    fn instantiate_identity_into(
483        self,
484        tcx: TyCtxt<'tcx>,
485        instantiated: &mut Vec<(ty::PolyTraitRef<'tcx>, Span)>,
486    ) {
487        if let Some(def_id) = self.parent {
488            tcx.const_conditions(def_id).instantiate_identity_into(tcx, instantiated);
489        }
490        instantiated.extend(self.predicates.iter().copied());
491    }
492}