Skip to main content

rustc_ast_lowering/delegation/
generics.rs

1use hir::HirId;
2use hir::def::{DefKind, Res};
3use rustc_ast::*;
4use rustc_hir as hir;
5use rustc_hir::def_id::DefId;
6use rustc_middle::ty::GenericParamDefKind;
7use rustc_middle::{bug, ty};
8use rustc_span::sym::{self};
9use rustc_span::symbol::kw;
10use rustc_span::{DUMMY_SP, Ident, Span};
11use thin_vec::{ThinVec, thin_vec};
12
13use crate::{AstOwner, LoweringContext};
14
15pub(super) enum DelegationGenerics<T> {
16    /// User-specified args are present: `reuse foo::<String>;`.
17    UserSpecified,
18    /// The default case when no user-specified args are present: `reuse Trait::foo;`.
19    Default(Option<T>),
20    /// In free-to-trait reuse, when user specified args for trait `reuse Trait::<i32>::foo;`
21    /// in this case we need to both generate `Self` and process user args.
22    SelfAndUserSpecified(Option<T>),
23}
24
25/// Used for storing either AST generics or their lowered HIR version. Firstly we obtain
26/// AST generics either from local function from AST index or from external function
27/// through `tcx`. Next, at some point of generics processing we need to lower those
28/// generics to HIR, for this purpose we use `into_hir_generics` that lowers AST generics
29/// and replaces Ast variant with Hir. Such approach is useful as we can call this method
30/// at any time knowing that lowering will occur at most only once. Then, in order to obtain generic
31/// params or args we use `hir_generics_or_empty` or `into_generic_args` functions.
32/// There also may be situations when we obtained AST generics but never lowered them to HIR,
33/// meaning we did not propagate them and thus we do not need to generate generic params
34/// (i.e., method call scenarios), in such a case this approach helps
35/// a lot as if `into_hir_generics` will not be called then lowering will not happen.
36pub(super) enum HirOrAstGenerics<'hir> {
37    Ast(DelegationGenerics<Generics>),
38    Hir(DelegationGenerics<&'hir hir::Generics<'hir>>),
39}
40
41pub(super) struct GenericsGenerationResult<'hir> {
42    pub(super) generics: HirOrAstGenerics<'hir>,
43    pub(super) args_segment_id: Option<HirId>,
44}
45
46pub(super) struct GenericsGenerationResults<'hir> {
47    pub(super) parent: GenericsGenerationResult<'hir>,
48    pub(super) child: GenericsGenerationResult<'hir>,
49}
50
51impl<T> DelegationGenerics<T> {
52    fn is_user_specified(&self) -> bool {
53        #[allow(non_exhaustive_omitted_patterns)] match self {
    DelegationGenerics::UserSpecified |
        DelegationGenerics::SelfAndUserSpecified { .. } => true,
    _ => false,
}matches!(
54            self,
55            DelegationGenerics::UserSpecified | DelegationGenerics::SelfAndUserSpecified { .. }
56        )
57    }
58}
59
60impl<'hir> HirOrAstGenerics<'hir> {
61    pub(super) fn into_hir_generics(
62        &mut self,
63        ctx: &mut LoweringContext<'_, 'hir>,
64        item_id: NodeId,
65        span: Span,
66    ) -> &mut HirOrAstGenerics<'hir> {
67        if let HirOrAstGenerics::Ast(generics) = self {
68            let process_params = |generics: &mut Generics| {
69                ctx.lower_delegation_generic_params(item_id, span, &mut generics.params)
70            };
71
72            let hir_generics = match generics {
73                DelegationGenerics::UserSpecified => DelegationGenerics::UserSpecified,
74                DelegationGenerics::Default(generics) => {
75                    DelegationGenerics::Default(generics.as_mut().map(process_params))
76                }
77                DelegationGenerics::SelfAndUserSpecified(generics) => {
78                    DelegationGenerics::SelfAndUserSpecified(generics.as_mut().map(process_params))
79                }
80            };
81
82            *self = HirOrAstGenerics::Hir(hir_generics);
83        }
84
85        self
86    }
87
88    fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> {
89        match self {
90            HirOrAstGenerics::Ast(_) => hir::Generics::empty(),
91            HirOrAstGenerics::Hir(hir_generics) => match hir_generics {
92                DelegationGenerics::UserSpecified => hir::Generics::empty(),
93                DelegationGenerics::Default(generics)
94                | DelegationGenerics::SelfAndUserSpecified(generics) => {
95                    generics.unwrap_or(hir::Generics::empty())
96                }
97            },
98        }
99    }
100
101    pub(super) fn into_generic_args(
102        &self,
103        ctx: &mut LoweringContext<'_, 'hir>,
104        add_lifetimes: bool,
105        span: Span,
106    ) -> Option<&'hir hir::GenericArgs<'hir>> {
107        match self {
108            HirOrAstGenerics::Ast(_) => {
109                ::rustc_middle::util::bug::bug_fmt(format_args!("Attempting to get generic args before lowering to HIR"))bug!("Attempting to get generic args before lowering to HIR")
110            }
111            HirOrAstGenerics::Hir(hir_generics) => match hir_generics {
112                DelegationGenerics::UserSpecified => None,
113                DelegationGenerics::Default(generics)
114                | DelegationGenerics::SelfAndUserSpecified(generics) => generics.map(|generics| {
115                    ctx.create_generics_args_from_params(generics.params, add_lifetimes, span)
116                }),
117            },
118        }
119    }
120
121    pub(super) fn is_user_specified(&self) -> bool {
122        match self {
123            HirOrAstGenerics::Ast(ast_generics) => ast_generics.is_user_specified(),
124            HirOrAstGenerics::Hir(hir_generics) => hir_generics.is_user_specified(),
125        }
126    }
127}
128
129impl<'a> GenericsGenerationResult<'a> {
130    fn new(generics: DelegationGenerics<Generics>) -> GenericsGenerationResult<'a> {
131        GenericsGenerationResult {
132            generics: HirOrAstGenerics::Ast(generics),
133            args_segment_id: None,
134        }
135    }
136}
137
138impl<'hir> GenericsGenerationResults<'hir> {
139    pub(super) fn all_params(
140        &mut self,
141        item_id: NodeId,
142        span: Span,
143        ctx: &mut LoweringContext<'_, 'hir>,
144    ) -> impl Iterator<Item = hir::GenericParam<'hir>> {
145        // Now we always call `into_hir_generics` both on child and parent,
146        // however in future we would not do that, when scenarios like
147        // method call will be supported (if HIR generics were not obtained
148        // then it means that we did not propagated them, thus we do not need
149        // to generate params).
150        let parent = self
151            .parent
152            .generics
153            .into_hir_generics(ctx, item_id, span)
154            .hir_generics_or_empty()
155            .params;
156
157        let child = self
158            .child
159            .generics
160            .into_hir_generics(ctx, item_id, span)
161            .hir_generics_or_empty()
162            .params;
163
164        // Order generics, firstly we have parent and child lifetimes,
165        // then parent and child types and consts.
166        // `generics_of` in `rustc_hir_analysis` will order them anyway,
167        // however we want the order to be consistent in HIR too.
168        parent
169            .iter()
170            .filter(|p| p.is_lifetime())
171            .chain(child.iter().filter(|p| p.is_lifetime()))
172            .chain(parent.iter().filter(|p| !p.is_lifetime()))
173            .chain(child.iter().filter(|p| !p.is_lifetime()))
174            .copied()
175    }
176
177    /// As we add hack predicates(`'a: 'a`) for all lifetimes (see `lower_delegation_generic_params`
178    /// and `generate_lifetime_predicate` functions) we need to add them to delegation generics.
179    /// Those predicates will not affect resulting predicate inheritance and folding
180    /// in `rustc_hir_analysis`, as we inherit all predicates from delegation signature.
181    pub(super) fn all_predicates(
182        &mut self,
183        item_id: NodeId,
184        span: Span,
185        ctx: &mut LoweringContext<'_, 'hir>,
186    ) -> impl Iterator<Item = hir::WherePredicate<'hir>> {
187        // Now we always call `into_hir_generics` both on child and parent,
188        // however in future we would not do that, when scenarios like
189        // method call will be supported (if HIR generics were not obtained
190        // then it means that we did not propagated them, thus we do not need
191        // to generate predicates).
192        self.parent
193            .generics
194            .into_hir_generics(ctx, item_id, span)
195            .hir_generics_or_empty()
196            .predicates
197            .into_iter()
198            .chain(
199                self.child
200                    .generics
201                    .into_hir_generics(ctx, item_id, span)
202                    .hir_generics_or_empty()
203                    .predicates
204                    .into_iter(),
205            )
206            .copied()
207    }
208}
209
210impl<'hir> LoweringContext<'_, 'hir> {
211    pub(super) fn lower_delegation_generics(
212        &mut self,
213        delegation: &Delegation,
214        root_fn_id: DefId,
215        item_id: NodeId,
216        span: Span,
217    ) -> GenericsGenerationResults<'hir> {
218        let delegation_in_free_ctx = !#[allow(non_exhaustive_omitted_patterns)] match self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id)))
    {
    DefKind::Trait | DefKind::Impl { .. } => true,
    _ => false,
}matches!(
219            self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id))),
220            DefKind::Trait | DefKind::Impl { .. }
221        );
222
223        let root_function_in_trait =
224            #[allow(non_exhaustive_omitted_patterns)] match self.tcx.def_kind(self.tcx.parent(root_fn_id))
    {
    DefKind::Trait => true,
    _ => false,
}matches!(self.tcx.def_kind(self.tcx.parent(root_fn_id)), DefKind::Trait);
225
226        let generate_self = delegation_in_free_ctx && root_function_in_trait;
227
228        let parent_generics_factory = |this: &mut Self, user_specified: bool| {
229            this.get_parent_generics(
230                this.tcx.parent(root_fn_id),
231                generate_self,
232                user_specified,
233                span,
234            )
235        };
236
237        let segments = &delegation.path.segments;
238        let len = segments.len();
239
240        let can_add_generics_to_parent = len >= 2
241            && self.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| {
242                #[allow(non_exhaustive_omitted_patterns)] match self.tcx.def_kind(def_id) {
    DefKind::Trait | DefKind::TraitAlias => true,
    _ => false,
}matches!(self.tcx.def_kind(def_id), DefKind::Trait | DefKind::TraitAlias)
243            });
244
245        let parent_generics = if can_add_generics_to_parent {
246            if segments[len - 2].args.is_some() {
247                if generate_self {
248                    DelegationGenerics::SelfAndUserSpecified(parent_generics_factory(self, true))
249                } else {
250                    DelegationGenerics::UserSpecified
251                }
252            } else {
253                DelegationGenerics::Default(parent_generics_factory(self, false))
254            }
255        } else {
256            DelegationGenerics::Default(None)
257        };
258
259        let child_generics = if segments[len - 1].args.is_some() {
260            DelegationGenerics::UserSpecified
261        } else {
262            DelegationGenerics::Default(self.get_fn_like_generics(root_fn_id, span))
263        };
264
265        GenericsGenerationResults {
266            parent: GenericsGenerationResult::new(parent_generics),
267            child: GenericsGenerationResult::new(child_generics),
268        }
269    }
270
271    fn lower_delegation_generic_params(
272        &mut self,
273        item_id: NodeId,
274        span: Span,
275        params: &mut ThinVec<GenericParam>,
276    ) -> &'hir hir::Generics<'hir> {
277        for p in params.iter_mut() {
278            // We want to create completely new params, so we generate
279            // a new id, otherwise assertions will be triggered.
280            p.id = self.next_node_id();
281
282            // Remove default params, as they are not supported on functions
283            // and there will duplicate DefId  when we try to lower them later.
284            match &mut p.kind {
285                GenericParamKind::Lifetime => {}
286                GenericParamKind::Type { default } => *default = None,
287                GenericParamKind::Const { default, .. } => *default = None,
288            }
289
290            // Note that we use self.disambiguator here, if we will create new every time
291            // we will get ICE if params have the same name.
292            self.resolver.node_id_to_def_id.insert(
293                p.id,
294                self.tcx
295                    .create_def(
296                        self.resolver.node_id_to_def_id[&item_id],
297                        Some(p.ident.name),
298                        match p.kind {
299                            GenericParamKind::Lifetime => DefKind::LifetimeParam,
300                            GenericParamKind::Type { .. } => DefKind::TyParam,
301                            GenericParamKind::Const { .. } => DefKind::ConstParam,
302                        },
303                        None,
304                        &mut self.disambiguator,
305                    )
306                    .def_id(),
307            );
308        }
309
310        // Fallback to default generic param lowering, we modified them in the loop above.
311        let params = self.arena.alloc_from_iter(
312            params.iter().map(|p| self.lower_generic_param(p, hir::GenericParamSource::Generics)),
313        );
314
315        // HACK: for now we generate predicates such that all lifetimes are early bound,
316        // we can not not generate early-bound lifetimes, but we can't know which of them
317        // are late-bound at this level of compilation.
318        // FIXME(fn_delegation): proper support for late bound lifetimes.
319        self.arena.alloc(hir::Generics {
320            params,
321            predicates: self.arena.alloc_from_iter(
322                params
323                    .iter()
324                    .filter_map(|p| p.is_lifetime().then(|| self.generate_lifetime_predicate(p))),
325            ),
326            has_where_clause_predicates: false,
327            where_clause_span: span,
328            span,
329        })
330    }
331
332    fn generate_lifetime_predicate(
333        &mut self,
334        p: &hir::GenericParam<'hir>,
335    ) -> hir::WherePredicate<'hir> {
336        let create_lifetime = |this: &mut Self| -> &'hir hir::Lifetime {
337            this.arena.alloc(hir::Lifetime {
338                hir_id: this.next_id(),
339                ident: p.name.ident(),
340                kind: rustc_hir::LifetimeKind::Param(p.def_id),
341                source: rustc_hir::LifetimeSource::Path {
342                    angle_brackets: rustc_hir::AngleBrackets::Full,
343                },
344                syntax: rustc_hir::LifetimeSyntax::ExplicitBound,
345            })
346        };
347
348        hir::WherePredicate {
349            hir_id: self.next_id(),
350            span: DUMMY_SP,
351            kind: self.arena.alloc(hir::WherePredicateKind::RegionPredicate(
352                hir::WhereRegionPredicate {
353                    in_where_clause: true,
354                    lifetime: create_lifetime(self),
355                    bounds: self
356                        .arena
357                        .alloc_slice(&[hir::GenericBound::Outlives(create_lifetime(self))]),
358                },
359            )),
360        }
361    }
362
363    fn create_generics_args_from_params(
364        &mut self,
365        params: &[hir::GenericParam<'hir>],
366        add_lifetimes: bool,
367        span: Span,
368    ) -> &'hir hir::GenericArgs<'hir> {
369        self.arena.alloc(hir::GenericArgs {
370            args: self.arena.alloc_from_iter(params.iter().filter_map(|p| {
371                // Skip self generic arg, we do not need to propagate it.
372                if p.name.ident().name == kw::SelfUpper {
373                    return None;
374                }
375
376                let create_path = |this: &mut Self| {
377                    let res = Res::Def(
378                        match p.kind {
379                            hir::GenericParamKind::Lifetime { .. } => DefKind::LifetimeParam,
380                            hir::GenericParamKind::Type { .. } => DefKind::TyParam,
381                            hir::GenericParamKind::Const { .. } => DefKind::ConstParam,
382                        },
383                        p.def_id.to_def_id(),
384                    );
385
386                    hir::QPath::Resolved(
387                        None,
388                        self.arena.alloc(hir::Path {
389                            segments: this.arena.alloc_slice(&[hir::PathSegment {
390                                args: None,
391                                hir_id: this.next_id(),
392                                ident: p.name.ident(),
393                                infer_args: false,
394                                res,
395                            }]),
396                            res,
397                            span: p.span,
398                        }),
399                    )
400                };
401
402                match p.kind {
403                    hir::GenericParamKind::Lifetime { .. } => match add_lifetimes {
404                        true => Some(hir::GenericArg::Lifetime(self.arena.alloc(hir::Lifetime {
405                            hir_id: self.next_id(),
406                            ident: p.name.ident(),
407                            kind: hir::LifetimeKind::Param(p.def_id),
408                            source: hir::LifetimeSource::Path {
409                                angle_brackets: hir::AngleBrackets::Full,
410                            },
411                            syntax: hir::LifetimeSyntax::ExplicitBound,
412                        }))),
413                        false => None,
414                    },
415                    hir::GenericParamKind::Type { .. } => {
416                        Some(hir::GenericArg::Type(self.arena.alloc(hir::Ty {
417                            hir_id: self.next_id(),
418                            span: p.span,
419                            kind: hir::TyKind::Path(create_path(self)),
420                        })))
421                    }
422                    hir::GenericParamKind::Const { .. } => {
423                        Some(hir::GenericArg::Const(self.arena.alloc(hir::ConstArg {
424                            hir_id: self.next_id(),
425                            kind: hir::ConstArgKind::Path(create_path(self)),
426                            span: p.span,
427                        })))
428                    }
429                }
430            })),
431            constraints: &[],
432            parenthesized: hir::GenericArgsParentheses::No,
433            span_ext: span,
434        })
435    }
436
437    fn get_fn_like_generics(&mut self, id: DefId, span: Span) -> Option<Generics> {
438        if let Some(local_id) = id.as_local() {
439            match self.ast_index.get(local_id) {
440                Some(AstOwner::Item(item)) if let ItemKind::Fn(f) = &item.kind => {
441                    Some(f.generics.clone())
442                }
443                Some(AstOwner::AssocItem(item, _)) if let AssocItemKind::Fn(f) = &item.kind => {
444                    Some(f.generics.clone())
445                }
446                _ => None,
447            }
448        } else {
449            self.get_external_generics(id, false, span)
450        }
451    }
452
453    fn get_external_generics(
454        &mut self,
455        id: DefId,
456        processing_parent: bool,
457        span: Span,
458    ) -> Option<Generics> {
459        let generics = self.tcx.generics_of(id);
460        if generics.own_params.is_empty() {
461            return None;
462        }
463
464        // Skip first Self parameter if we are in trait, it will be added later.
465        let to_skip = (processing_parent && generics.has_self) as usize;
466
467        Some(Generics {
468            params: generics
469                .own_params
470                .iter()
471                .skip(to_skip)
472                .map(|p| GenericParam {
473                    attrs: Default::default(),
474                    bounds: Default::default(),
475                    colon_span: None,
476                    id: self.next_node_id(),
477                    ident: Ident::with_dummy_span(p.name),
478                    is_placeholder: false,
479                    kind: match p.kind {
480                        GenericParamDefKind::Lifetime => GenericParamKind::Lifetime,
481                        GenericParamDefKind::Type { .. } => {
482                            GenericParamKind::Type { default: None }
483                        }
484                        GenericParamDefKind::Const { .. } => self.map_const_kind(p, span),
485                    },
486                })
487                .collect(),
488            where_clause: Default::default(),
489            span: DUMMY_SP,
490        })
491    }
492
493    fn map_const_kind(&mut self, p: &ty::GenericParamDef, span: Span) -> GenericParamKind {
494        let const_type = self.tcx.type_of(p.def_id).instantiate_identity();
495
496        let (type_symbol, res) = match const_type.kind() {
497            ty::Bool => (sym::bool, Res::PrimTy(hir::PrimTy::Bool)),
498            ty::Uint(uint) => (uint.name(), Res::PrimTy(hir::PrimTy::Uint(*uint))),
499            ty::Int(int) => (int.name(), Res::PrimTy(hir::PrimTy::Int(*int))),
500            ty::Char => (sym::char, Res::PrimTy(hir::PrimTy::Char)),
501            _ => {
502                self.tcx
503                    .dcx()
504                    .span_delayed_bug(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Unexpected const type: {0}",
                const_type))
    })format!("Unexpected const type: {}", const_type));
505
506                (sym::dummy, Res::Err)
507            }
508        };
509
510        let node_id = self.next_node_id();
511
512        self.resolver.partial_res_map.insert(node_id, hir::def::PartialRes::new(res));
513
514        GenericParamKind::Const {
515            ty: Box::new(Ty {
516                id: node_id,
517                kind: TyKind::Path(
518                    None,
519                    Path {
520                        segments: {
    let len = [()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(PathSegment {
            ident: Ident::with_dummy_span(type_symbol),
            id: self.next_node_id(),
            args: None,
        });
    vec
}thin_vec![PathSegment {
521                            ident: Ident::with_dummy_span(type_symbol),
522                            id: self.next_node_id(),
523                            args: None
524                        }],
525                        span: DUMMY_SP,
526                        tokens: None,
527                    },
528                ),
529                span: DUMMY_SP,
530                tokens: None,
531            }),
532            span: DUMMY_SP,
533            default: None,
534        }
535    }
536
537    fn get_parent_generics(
538        &mut self,
539        id: DefId,
540        add_self: bool,
541        user_specified: bool,
542        span: Span,
543    ) -> Option<Generics> {
544        // If args are user-specified we still maybe need to add self.
545        let mut generics = if user_specified {
546            None
547        } else {
548            if let Some(local_id) = id.as_local() {
549                if let Some(AstOwner::Item(item)) = self.ast_index.get(local_id)
550                    && #[allow(non_exhaustive_omitted_patterns)] match item.kind {
    ItemKind::Trait(..) => true,
    _ => false,
}matches!(item.kind, ItemKind::Trait(..))
551                {
552                    item.opt_generics().cloned()
553                } else {
554                    None
555                }
556            } else {
557                self.get_external_generics(id, true, span)
558            }
559        };
560
561        if add_self {
562            generics.get_or_insert_default().params.insert(
563                0,
564                GenericParam {
565                    id: self.next_node_id(),
566                    ident: Ident::new(kw::SelfUpper, DUMMY_SP),
567                    attrs: Default::default(),
568                    bounds: ::alloc::vec::Vec::new()vec![],
569                    is_placeholder: false,
570                    kind: GenericParamKind::Type { default: None },
571                    colon_span: None,
572                },
573            );
574        }
575
576        generics
577    }
578}