Skip to main content

rustc_hir_analysis/collect/
generics_of.rs

1use std::ops::ControlFlow;
2
3use rustc_data_structures::assert_matches;
4use rustc_hir::def::DefKind;
5use rustc_hir::def_id::LocalDefId;
6use rustc_hir::intravisit::{self, Visitor, VisitorExt};
7use rustc_hir::{self as hir, AmbigArg, GenericParamKind, HirId, Node};
8use rustc_middle::span_bug;
9use rustc_middle::ty::{self, TyCtxt};
10use rustc_session::lint;
11use rustc_span::{Span, Symbol, kw};
12use tracing::{debug, instrument};
13
14use crate::middle::resolve_bound_vars as rbv;
15
16x;#[instrument(level = "debug", skip(tcx), ret)]
17pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
18    use rustc_hir::*;
19
20    // For an RPITIT, synthesize generics which are equal to the opaque's generics
21    // and parent fn's generics compressed into one list.
22    if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) =
23        tcx.opt_rpitit_info(def_id.to_def_id())
24    {
25        debug!("RPITIT fn_def_id={fn_def_id:?} opaque_def_id={opaque_def_id:?}");
26        let trait_def_id = tcx.parent(fn_def_id);
27        let opaque_ty_generics = tcx.generics_of(opaque_def_id);
28        let opaque_ty_parent_count = opaque_ty_generics.parent_count;
29        let mut own_params = opaque_ty_generics.own_params.clone();
30
31        let parent_generics = tcx.generics_of(trait_def_id);
32        let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
33
34        let mut trait_fn_params = tcx.generics_of(fn_def_id).own_params.clone();
35
36        for param in &mut own_params {
37            param.index = param.index + parent_count as u32 + trait_fn_params.len() as u32
38                - opaque_ty_parent_count as u32;
39        }
40
41        trait_fn_params.extend(own_params);
42        own_params = trait_fn_params;
43
44        let param_def_id_to_index =
45            own_params.iter().map(|param| (param.def_id, param.index)).collect();
46
47        return ty::Generics {
48            parent: Some(trait_def_id),
49            parent_count,
50            own_params,
51            param_def_id_to_index,
52            has_self: opaque_ty_generics.has_self,
53            has_late_bound_regions: opaque_ty_generics.has_late_bound_regions,
54        };
55    }
56
57    let hir_id = tcx.local_def_id_to_hir_id(def_id);
58    let node = tcx.hir_node(hir_id);
59
60    let parent_def_id = match node {
61        Node::ImplItem(_)
62        | Node::TraitItem(_)
63        | Node::Variant(_)
64        | Node::Ctor(..)
65        | Node::Field(_) => {
66            let parent_id = tcx.hir_get_parent_item(hir_id);
67            Some(parent_id.to_def_id())
68        }
69        // FIXME(#43408) always enable this once `lazy_normalization` is
70        // stable enough and does not need a feature gate anymore.
71        Node::AnonConst(_) => {
72            let parent_did = tcx.parent(def_id.to_def_id());
73            debug!(?parent_did);
74
75            let mut in_param_ty = false;
76            for (_parent, node) in tcx.hir_parent_iter(hir_id) {
77                if let Some(generics) = node.generics() {
78                    let mut visitor = AnonConstInParamTyDetector { in_param_ty: false, ct: hir_id };
79
80                    in_param_ty = visitor.visit_generics(generics).is_break();
81                    break;
82                }
83            }
84
85            match tcx.anon_const_kind(def_id) {
86                // Stable: anon consts are not able to use any generic parameters...
87                ty::AnonConstKind::MCG => None,
88                // OGCA anon consts inherit their parent's generics.
89                ty::AnonConstKind::OGCA => Some(parent_did),
90                // we provide generics to repeat expr counts as a backwards compatibility hack. #76200
91                ty::AnonConstKind::RepeatExprCount => Some(parent_did),
92
93                // Even GCE anon const should not be allowed to use generic parameters as it would be
94                // trivially forward declared uses once desugared. E.g. `const N: [u8; ANON::<N>]`.
95                //
96                // We could potentially mirror the hack done for defaults of generic parameters but
97                // this case just doesn't come up much compared to `const N: u32 = ...`. Long term the
98                // hack for defaulted parameters should be removed eventually anyway.
99                ty::AnonConstKind::GCE if in_param_ty => None,
100                // GCE anon consts as a default for a generic parameter should have their provided generics
101                // "truncated" up to whatever generic parameter this anon const is within the default of.
102                //
103                // FIXME(generic_const_exprs): This only handles `const N: usize = /*defid*/` but not type
104                // parameter defaults, e.g. `T = Foo</*defid*/>`.
105                ty::AnonConstKind::GCE
106                    if let Some(param_id) =
107                        tcx.hir_opt_const_param_default_param_def_id(hir_id) =>
108                {
109                    // If the def_id we are calling generics_of on is an anon ct default i.e:
110                    //
111                    // struct Foo<const N: usize = { .. }>;
112                    //        ^^^       ^          ^^^^^^ def id of this anon const
113                    //        ^         ^ param_id
114                    //        ^ parent_def_id
115                    //
116                    // then we only want to return generics for params to the left of `N`. If we don't do that we
117                    // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, args: [N#0])`.
118                    //
119                    // This causes ICEs (#86580) when building the args for Foo in `fn foo() -> Foo { .. }` as
120                    // we instantiate the defaults with the partially built args when we build the args. Instantiating
121                    // the `N#0` on the unevaluated const indexes into the empty args we're in the process of building.
122                    //
123                    // We fix this by having this function return the parent's generics ourselves and truncating the
124                    // generics to only include non-forward declared params (with the exception of the `Self` ty)
125                    //
126                    // For the above code example that means we want `args: []`
127                    // For the following struct def we want `args: [N#0]` when generics_of is called on
128                    // the def id of the `{ N + 1 }` anon const
129                    // struct Foo<const N: usize, const M: usize = { N + 1 }>;
130                    //
131                    // This has some implications for how we get the predicates available to the anon const
132                    // see `explicit_predicates_of` for more information on this
133                    let generics = tcx.generics_of(parent_did);
134                    let param_def_idx = generics.param_def_id_to_index[&param_id.to_def_id()];
135                    // In the above example this would be .params[..N#0]
136                    let own_params = generics.params_to(param_def_idx as usize, tcx).to_owned();
137                    let param_def_id_to_index =
138                        own_params.iter().map(|param| (param.def_id, param.index)).collect();
139
140                    return ty::Generics {
141                        // we set the parent of these generics to be our parent's parent so that we
142                        // dont end up with args: [N, M, N] for the const default on a struct like this:
143                        // struct Foo<const N: usize, const M: usize = { ... }>;
144                        parent: generics.parent,
145                        parent_count: generics.parent_count,
146                        own_params,
147                        param_def_id_to_index,
148                        has_self: generics.has_self,
149                        has_late_bound_regions: generics.has_late_bound_regions,
150                    };
151                }
152                ty::AnonConstKind::GCE => Some(parent_did),
153
154                // Field defaults are allowed to use generic parameters, e.g. `field: u32 = /*defid: N + 1*/`
155                ty::AnonConstKind::NonTypeSystem
156                    if matches!(tcx.parent_hir_node(hir_id), Node::TyPat(_) | Node::Field(_)) =>
157                {
158                    Some(parent_did)
159                }
160                // Default to no generic parameters for other kinds of anon consts
161                ty::AnonConstKind::NonTypeSystem => None,
162            }
163        }
164        Node::ConstBlock(_)
165        | Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
166            Some(tcx.typeck_root_def_id(def_id.to_def_id()))
167        }
168        Node::OpaqueTy(&hir::OpaqueTy {
169            origin:
170                hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, in_trait_or_impl }
171                | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl },
172            ..
173        }) => {
174            if in_trait_or_impl.is_some() {
175                assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn);
176            } else {
177                assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn);
178            }
179            Some(fn_def_id.to_def_id())
180        }
181        Node::OpaqueTy(&hir::OpaqueTy {
182            origin: hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty },
183            ..
184        }) => {
185            if in_assoc_ty {
186                assert_matches!(tcx.def_kind(parent), DefKind::AssocTy);
187            } else {
188                assert_matches!(tcx.def_kind(parent), DefKind::TyAlias);
189            }
190            debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent);
191            // Opaque types are always nested within another item, and
192            // inherit the generics of the item.
193            Some(parent.to_def_id())
194        }
195
196        // All of these nodes have no parent from which to inherit generics.
197        Node::Item(_) | Node::ForeignItem(_) => None,
198
199        // Params don't really have generics, but we use it when instantiating their value paths.
200        Node::GenericParam(_) => None,
201
202        Node::Synthetic => span_bug!(
203            tcx.def_span(def_id),
204            "synthetic HIR should have its `generics_of` explicitly fed"
205        ),
206
207        _ => span_bug!(tcx.def_span(def_id), "generics_of: unexpected node kind {node:?}"),
208    };
209
210    // Add in the self type parameter.
211    let opt_self = if let Node::Item(item) = node
212        && let ItemKind::Trait(..) | ItemKind::TraitAlias(..) = item.kind
213    {
214        // Something of a hack: We reuse the node ID of the trait for the self type parameter.
215        Some(ty::GenericParamDef {
216            index: 0,
217            name: kw::SelfUpper,
218            def_id: def_id.to_def_id(),
219            pure_wrt_drop: false,
220            kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
221        })
222    } else {
223        None
224    };
225
226    let param_default_policy = param_default_policy(node);
227    let hir_generics = node.generics().unwrap_or(hir::Generics::empty());
228    let has_self = opt_self.is_some();
229    let mut parent_has_self = false;
230    let mut own_start = has_self as u32;
231    let parent_count = parent_def_id.map_or(0, |def_id| {
232        let generics = tcx.generics_of(def_id);
233        assert!(!has_self);
234        parent_has_self = generics.has_self;
235        own_start = generics.count() as u32;
236        generics.parent_count + generics.own_params.len()
237    });
238
239    let mut own_params: Vec<_> = Vec::with_capacity(hir_generics.params.len() + has_self as usize);
240
241    if let Some(opt_self) = opt_self {
242        own_params.push(opt_self);
243    }
244
245    let early_lifetimes = super::early_bound_lifetimes_from_generics(tcx, hir_generics);
246    own_params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
247        name: param.name.ident().name,
248        index: own_start + i as u32,
249        def_id: param.def_id.to_def_id(),
250        pure_wrt_drop: param.pure_wrt_drop,
251        kind: ty::GenericParamDefKind::Lifetime,
252    }));
253
254    // Now create the real type and const parameters.
255    let type_start = own_start - has_self as u32 + own_params.len() as u32;
256    let mut i: u32 = 0;
257    let mut next_index = || {
258        let prev = i;
259        i += 1;
260        prev + type_start
261    };
262
263    own_params.extend(hir_generics.params.iter().filter_map(|param| {
264        const MESSAGE: &str = "defaults for generic parameters are not allowed here";
265        let kind = match param.kind {
266            GenericParamKind::Lifetime { .. } => return None,
267            GenericParamKind::Type { default, synthetic } => {
268                if default.is_some() {
269                    match param_default_policy.expect("no policy for generic param default") {
270                        ParamDefaultPolicy::Allowed => {}
271                        ParamDefaultPolicy::FutureCompatForbidden => {
272                            tcx.node_span_lint(
273                                lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
274                                param.hir_id,
275                                param.span,
276                                |lint| {
277                                    lint.primary_message(MESSAGE);
278                                },
279                            );
280                        }
281                        ParamDefaultPolicy::Forbidden => {
282                            tcx.dcx().span_err(param.span, MESSAGE);
283                        }
284                    }
285                }
286
287                ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic }
288            }
289            GenericParamKind::Const { ty: _, default } => {
290                if default.is_some() {
291                    match param_default_policy.expect("no policy for generic param default") {
292                        ParamDefaultPolicy::Allowed => {}
293                        ParamDefaultPolicy::FutureCompatForbidden
294                        | ParamDefaultPolicy::Forbidden => {
295                            tcx.dcx().span_err(param.span, MESSAGE);
296                        }
297                    }
298                }
299
300                ty::GenericParamDefKind::Const { has_default: default.is_some() }
301            }
302        };
303        Some(ty::GenericParamDef {
304            index: next_index(),
305            name: param.name.ident().name,
306            def_id: param.def_id.to_def_id(),
307            pure_wrt_drop: param.pure_wrt_drop,
308            kind,
309        })
310    }));
311
312    // provide junk type parameter defs - the only place that
313    // cares about anything but the length is instantiation,
314    // and we don't do that for closures.
315    if let Node::Expr(&hir::Expr {
316        kind: hir::ExprKind::Closure(hir::Closure { kind, .. }), ..
317    }) = node
318    {
319        // See `ClosureArgsParts`, `CoroutineArgsParts`, and `CoroutineClosureArgsParts`
320        // for info on the usage of each of these fields.
321        let dummy_args = match kind {
322            ClosureKind::Closure => &["<closure_kind>", "<closure_signature>", "<upvars>"][..],
323            ClosureKind::Coroutine(_) => {
324                &["<coroutine_kind>", "<resume_ty>", "<yield_ty>", "<return_ty>", "<upvars>"][..]
325            }
326            ClosureKind::CoroutineClosure(_) => &[
327                "<closure_kind>",
328                "<closure_signature_parts>",
329                "<upvars>",
330                "<bound_captures_by_ref>",
331            ][..],
332        };
333
334        own_params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
335            index: next_index(),
336            name: Symbol::intern(arg),
337            def_id: def_id.to_def_id(),
338            pure_wrt_drop: false,
339            kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
340        }));
341    }
342
343    // provide junk type parameter defs for const blocks.
344    if let Node::ConstBlock(_) = node {
345        own_params.push(ty::GenericParamDef {
346            index: next_index(),
347            name: rustc_span::sym::const_ty_placeholder,
348            def_id: def_id.to_def_id(),
349            pure_wrt_drop: false,
350            kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
351        });
352    }
353
354    if let Node::OpaqueTy(&hir::OpaqueTy { .. }) = node {
355        assert!(own_params.is_empty());
356
357        let lifetimes = tcx.opaque_captured_lifetimes(def_id);
358        debug!(?lifetimes);
359
360        own_params.extend(lifetimes.iter().map(|&(_, param)| ty::GenericParamDef {
361            name: tcx.item_name(param.to_def_id()),
362            index: next_index(),
363            def_id: param.to_def_id(),
364            pure_wrt_drop: false,
365            kind: ty::GenericParamDefKind::Lifetime,
366        }))
367    }
368
369    let param_def_id_to_index =
370        own_params.iter().map(|param| (param.def_id, param.index)).collect();
371
372    ty::Generics {
373        parent: parent_def_id,
374        parent_count,
375        own_params,
376        param_def_id_to_index,
377        has_self: has_self || parent_has_self,
378        has_late_bound_regions: has_late_bound_regions(tcx, node),
379    }
380}
381
382#[derive(#[automatically_derived]
impl ::core::clone::Clone for ParamDefaultPolicy {
    #[inline]
    fn clone(&self) -> ParamDefaultPolicy { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ParamDefaultPolicy { }Copy)]
383enum ParamDefaultPolicy {
384    Allowed,
385    /// Tracked in <https://github.com/rust-lang/rust/issues/36887>.
386    FutureCompatForbidden,
387    Forbidden,
388}
389
390fn param_default_policy(node: Node<'_>) -> Option<ParamDefaultPolicy> {
391    use rustc_hir::*;
392
393    Some(match node {
394        Node::Item(item) => match item.kind {
395            ItemKind::Trait(..)
396            | ItemKind::TraitAlias(..)
397            | ItemKind::TyAlias(..)
398            | ItemKind::Enum(..)
399            | ItemKind::Struct(..)
400            | ItemKind::Union(..) => ParamDefaultPolicy::Allowed,
401            ItemKind::Fn { .. } | ItemKind::Impl(_) => ParamDefaultPolicy::FutureCompatForbidden,
402            // Re. GCI, we're not bound by backward compatibility.
403            ItemKind::Const(..) => ParamDefaultPolicy::Forbidden,
404            _ => return None,
405        },
406        Node::TraitItem(item) => match item.kind {
407            // Re. GATs and GACs (generic_const_items), we're not bound by backward compatibility.
408            TraitItemKind::Const(..) | TraitItemKind::Type(..) => ParamDefaultPolicy::Forbidden,
409            TraitItemKind::Fn(..) => ParamDefaultPolicy::FutureCompatForbidden,
410        },
411        Node::ImplItem(item) => match item.kind {
412            // Re. GATs and GACs (generic_const_items), we're not bound by backward compatibility.
413            ImplItemKind::Const(..) | ImplItemKind::Type(..) => ParamDefaultPolicy::Forbidden,
414            ImplItemKind::Fn(..) => ParamDefaultPolicy::FutureCompatForbidden,
415        },
416        // Generic params are (semantically) invalid on foreign items. Still, for maximum forward
417        // compatibility, let's hard-reject defaults on them.
418        Node::ForeignItem(_) => ParamDefaultPolicy::Forbidden,
419        Node::OpaqueTy(..) => ParamDefaultPolicy::Allowed,
420        _ => return None,
421    })
422}
423
424fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> {
425    struct LateBoundRegionsDetector<'tcx> {
426        tcx: TyCtxt<'tcx>,
427        outer_index: ty::DebruijnIndex,
428    }
429
430    impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
431        type Result = ControlFlow<Span>;
432        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) -> ControlFlow<Span> {
433            match ty.kind {
434                hir::TyKind::FnPtr(..) => {
435                    self.outer_index.shift_in(1);
436                    let res = intravisit::walk_ty(self, ty);
437                    self.outer_index.shift_out(1);
438                    res
439                }
440                hir::TyKind::UnsafeBinder(_) => {
441                    self.outer_index.shift_in(1);
442                    let res = intravisit::walk_ty(self, ty);
443                    self.outer_index.shift_out(1);
444                    res
445                }
446                _ => intravisit::walk_ty(self, ty),
447            }
448        }
449
450        fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) -> ControlFlow<Span> {
451            self.outer_index.shift_in(1);
452            let res = intravisit::walk_poly_trait_ref(self, tr);
453            self.outer_index.shift_out(1);
454            res
455        }
456
457        fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) -> ControlFlow<Span> {
458            match self.tcx.named_bound_var(lt.hir_id) {
459                Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {
460                    ControlFlow::Continue(())
461                }
462                Some(rbv::ResolvedArg::LateBound(debruijn, _, _))
463                    if debruijn < self.outer_index =>
464                {
465                    ControlFlow::Continue(())
466                }
467                Some(
468                    rbv::ResolvedArg::LateBound(..)
469                    | rbv::ResolvedArg::Free(..)
470                    | rbv::ResolvedArg::Error(_),
471                )
472                | None => ControlFlow::Break(lt.ident.span),
473            }
474        }
475    }
476
477    fn has_late_bound_regions<'tcx>(
478        tcx: TyCtxt<'tcx>,
479        generics: &'tcx hir::Generics<'tcx>,
480        decl: &'tcx hir::FnDecl<'tcx>,
481    ) -> Option<Span> {
482        let mut visitor = LateBoundRegionsDetector { tcx, outer_index: ty::INNERMOST };
483        for param in generics.params {
484            if let GenericParamKind::Lifetime { .. } = param.kind {
485                if tcx.is_late_bound(param.hir_id) {
486                    return Some(param.span);
487                }
488            }
489        }
490        visitor.visit_fn_decl(decl).break_value()
491    }
492
493    let decl = node.fn_decl()?;
494    let generics = node.generics()?;
495    has_late_bound_regions(tcx, generics, decl)
496}
497
498struct AnonConstInParamTyDetector {
499    in_param_ty: bool,
500    ct: HirId,
501}
502
503impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
504    type Result = ControlFlow<()>;
505
506    fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result {
507        if let GenericParamKind::Const { ty, default: _ } = p.kind {
508            let prev = self.in_param_ty;
509            self.in_param_ty = true;
510            let res = self.visit_ty_unambig(ty);
511            self.in_param_ty = prev;
512            res
513        } else {
514            ControlFlow::Continue(())
515        }
516    }
517
518    fn visit_anon_const(&mut self, c: &'v hir::AnonConst) -> Self::Result {
519        if self.in_param_ty && self.ct == c.hir_id {
520            return ControlFlow::Break(());
521        }
522        intravisit::walk_anon_const(self, c)
523    }
524}