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::symbol::kw;
9use rustc_span::{Ident, Span, sym};
10
11use crate::LoweringContext;
12
13#[derive(#[automatically_derived]
impl ::core::clone::Clone for DelegationGenericsKind {
    #[inline]
    fn clone(&self) -> DelegationGenericsKind {
        let _: ::core::clone::AssertParamIsClone<bool>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DelegationGenericsKind { }Copy)]
14pub(super) enum DelegationGenericsKind {
15    /// User-specified args are present: `reuse foo::<String>;`.
16    UserSpecified,
17    /// The default case when no user-specified args are present: `reuse Trait::foo;`.
18    Default,
19    /// In free-to-trait reuse, when user specified args for trait `reuse Trait::<i32>::foo;`
20    /// in this case we need to both generate `Self` and process user args.
21    SelfAndUserSpecified,
22    /// In delegations from trait impl to other entities like free functions or trait functions,
23    /// we want to generate a function whose generics matches generics of signature function
24    /// in trait.
25    TraitImpl(bool /* Has user-specified args */),
26}
27
28#[derive(#[automatically_derived]
impl ::core::fmt::Debug for GenericsPosition {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                GenericsPosition::Parent => "Parent",
                GenericsPosition::Child => "Child",
            })
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for GenericsPosition {
    #[inline]
    fn clone(&self) -> GenericsPosition { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for GenericsPosition { }Copy)]
29pub(super) enum GenericsPosition {
30    Parent,
31    Child,
32}
33
34pub(super) struct DelegationGenerics<T> {
35    generics: T,
36    kind: DelegationGenericsKind,
37    pos: GenericsPosition,
38}
39
40impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> {
41    fn default(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {
42        DelegationGenerics { generics, pos, kind: DelegationGenericsKind::Default }
43    }
44
45    fn user_specified(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {
46        DelegationGenerics { generics, pos, kind: DelegationGenericsKind::UserSpecified }
47    }
48
49    fn trait_impl(
50        generics: &'hir [ty::GenericParamDef],
51        user_specified: bool,
52        pos: GenericsPosition,
53    ) -> Self {
54        DelegationGenerics {
55            generics,
56            pos,
57            kind: DelegationGenericsKind::TraitImpl(user_specified),
58        }
59    }
60}
61
62/// Used for storing either ty generics or their uplifted HIR version. First we obtain
63/// ty generics. Next, at some point of generics processing we need to uplift those
64/// generics to HIR, for this purpose we use `into_hir_generics` that uplifts ty generics
65/// and replaces Ty variant with Hir. Such approach is useful as we can call this method
66/// at any time knowing that uplifting will occur at most only once. Then, in order to obtain generic
67/// params or args we use `hir_generics_or_empty` or `into_generic_args` functions.
68/// There also may be situations when we obtained ty generics but never uplifted them to HIR,
69/// meaning we did not propagate them and thus we do not need to generate generic params
70/// (i.e., method call scenarios), in such a case this approach helps
71/// a lot as if `into_hir_generics` will not be called then uplifting will not happen.
72pub(super) enum HirOrTyGenerics<'hir> {
73    Ty(DelegationGenerics<&'hir [ty::GenericParamDef]>),
74    Hir(DelegationGenerics<&'hir hir::Generics<'hir>>),
75}
76
77pub(super) struct GenericsGenerationResult<'hir> {
78    pub(super) generics: HirOrTyGenerics<'hir>,
79    pub(super) args_segment_id: Option<HirId>,
80}
81
82pub(super) struct GenericsGenerationResults<'hir> {
83    pub(super) parent: GenericsGenerationResult<'hir>,
84    pub(super) child: GenericsGenerationResult<'hir>,
85    pub(super) self_ty_id: Option<HirId>,
86    pub(super) propagate_self_ty: bool,
87}
88
89pub(super) struct GenericArgsPropagationDetails {
90    pub(super) should_propagate: bool,
91    pub(super) use_args_in_sig_inheritance: bool,
92}
93
94impl DelegationGenericsKind {
95    fn args_propagation_details(self) -> GenericArgsPropagationDetails {
96        match self {
97            DelegationGenericsKind::UserSpecified
98            | DelegationGenericsKind::SelfAndUserSpecified => GenericArgsPropagationDetails {
99                should_propagate: false,
100                use_args_in_sig_inheritance: true,
101            },
102            DelegationGenericsKind::TraitImpl(user_specified) => GenericArgsPropagationDetails {
103                should_propagate: !user_specified,
104                use_args_in_sig_inheritance: false,
105            },
106            DelegationGenericsKind::Default => GenericArgsPropagationDetails {
107                should_propagate: true,
108                use_args_in_sig_inheritance: false,
109            },
110        }
111    }
112}
113
114impl<'hir> HirOrTyGenerics<'hir> {
115    pub(super) fn into_hir_generics(
116        &mut self,
117        ctx: &mut LoweringContext<'_, 'hir>,
118        span: Span,
119    ) -> &mut HirOrTyGenerics<'hir> {
120        if let HirOrTyGenerics::Ty(ty) = self {
121            let rename_self = #[allow(non_exhaustive_omitted_patterns)] match ty.pos {
    GenericsPosition::Child => true,
    _ => false,
}matches!(ty.pos, GenericsPosition::Child);
122            let params = ctx.uplift_delegation_generic_params(span, ty.generics, rename_self);
123
124            *self = HirOrTyGenerics::Hir(DelegationGenerics {
125                generics: params,
126                kind: ty.kind,
127                pos: ty.pos,
128            });
129        }
130
131        self
132    }
133
134    fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> {
135        match self {
136            HirOrTyGenerics::Ty(_) => hir::Generics::empty(),
137            HirOrTyGenerics::Hir(hir) => hir.generics,
138        }
139    }
140
141    pub(super) fn into_generic_args(
142        &self,
143        ctx: &mut LoweringContext<'_, 'hir>,
144        span: Span,
145    ) -> &'hir hir::GenericArgs<'hir> {
146        match self {
147            HirOrTyGenerics::Ty(_) => {
148                ::rustc_middle::util::bug::bug_fmt(format_args!("Attempting to get generic args before uplifting to HIR"))bug!("Attempting to get generic args before uplifting to HIR")
149            }
150            HirOrTyGenerics::Hir(hir) => {
151                let add_lifetimes = #[allow(non_exhaustive_omitted_patterns)] match hir.pos {
    GenericsPosition::Parent => true,
    _ => false,
}matches!(hir.pos, GenericsPosition::Parent);
152                ctx.create_generics_args_from_params(hir.generics.params, add_lifetimes, span)
153            }
154        }
155    }
156
157    pub(super) fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
158        match self {
159            HirOrTyGenerics::Ty(ty) => ty.kind.args_propagation_details(),
160            HirOrTyGenerics::Hir(hir) => hir.kind.args_propagation_details(),
161        }
162    }
163}
164
165impl<'hir> GenericsGenerationResult<'hir> {
166    fn new(
167        generics: DelegationGenerics<&'hir [ty::GenericParamDef]>,
168    ) -> GenericsGenerationResult<'hir> {
169        GenericsGenerationResult { generics: HirOrTyGenerics::Ty(generics), args_segment_id: None }
170    }
171}
172
173impl<'hir> GenericsGenerationResults<'hir> {
174    pub(super) fn all_params(
175        &mut self,
176        span: Span,
177        ctx: &mut LoweringContext<'_, 'hir>,
178    ) -> impl Iterator<Item = hir::GenericParam<'hir>> {
179        // Now we always call `into_hir_generics` both on child and parent,
180        // however in future we would not do that, when scenarios like
181        // method call will be supported (if HIR generics were not obtained
182        // then it means that we did not propagated them, thus we do not need
183        // to generate params).
184        let mut create_params = |result: &mut GenericsGenerationResult<'hir>| {
185            result.generics.into_hir_generics(ctx, span).hir_generics_or_empty().params
186        };
187
188        let parent = create_params(&mut self.parent);
189        let child = create_params(&mut self.child);
190
191        // Order generics, first we have parent and child lifetimes,
192        // then parent and child types and consts.
193        // `generics_of` in `rustc_hir_analysis` will order them anyway,
194        // however we want the order to be consistent in HIR too.
195        parent
196            .iter()
197            .filter(|p| p.is_lifetime())
198            .chain(child.iter().filter(|p| p.is_lifetime()))
199            .chain(parent.iter().filter(|p| !p.is_lifetime()))
200            .chain(child.iter().filter(|p| !p.is_lifetime()))
201            .copied()
202    }
203
204    /// As we add hack predicates(`'a: 'a`) for all lifetimes (see `uplift_delegation_generic_params`
205    /// and `generate_lifetime_predicate` functions) we need to add them to delegation generics.
206    /// Those predicates will not affect resulting predicate inheritance and folding
207    /// in `rustc_hir_analysis`, as we inherit all predicates from delegation signature.
208    pub(super) fn all_predicates(
209        &mut self,
210        span: Span,
211        ctx: &mut LoweringContext<'_, 'hir>,
212    ) -> impl Iterator<Item = hir::WherePredicate<'hir>> {
213        // Now we always call `into_hir_generics` both on child and parent,
214        // however in future we would not do that, when scenarios like
215        // method call will be supported (if HIR generics were not obtained
216        // then it means that we did not propagated them, thus we do not need
217        // to generate predicates).
218        let mut create_predicates = |result: &mut GenericsGenerationResult<'hir>| {
219            result.generics.into_hir_generics(ctx, span).hir_generics_or_empty().predicates
220        };
221
222        let parent = create_predicates(&mut self.parent);
223        let child = create_predicates(&mut self.child);
224
225        parent.into_iter().chain(child).copied()
226    }
227}
228
229impl<'hir> LoweringContext<'_, 'hir> {
230    pub(super) fn uplift_delegation_generics(
231        &mut self,
232        delegation: &Delegation,
233        sig_id: DefId,
234        item_id: NodeId,
235        is_method: bool,
236    ) -> GenericsGenerationResults<'hir> {
237        let delegation_parent_kind =
238            self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id)));
239
240        let segments = &delegation.path.segments;
241        let len = segments.len();
242        let child_user_specified = segments[len - 1].args.is_some();
243
244        let sig_params = &self.tcx.generics_of(sig_id).own_params[..];
245
246        // If we are in trait impl always generate function whose generics matches
247        // those that are defined in trait.
248        if #[allow(non_exhaustive_omitted_patterns)] match delegation_parent_kind {
    DefKind::Impl { of_trait: true } => true,
    _ => false,
}matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {
249            // Considering parent generics, during signature inheritance
250            // we will take those args that are in trait impl header trait ref.
251            let parent = DelegationGenerics::trait_impl(&[], true, GenericsPosition::Parent);
252            let parent = GenericsGenerationResult::new(parent);
253
254            let child = DelegationGenerics::trait_impl(
255                sig_params,
256                child_user_specified,
257                GenericsPosition::Child,
258            );
259
260            let child = GenericsGenerationResult::new(child);
261
262            return GenericsGenerationResults {
263                parent,
264                child,
265                self_ty_id: None,
266                propagate_self_ty: false,
267            };
268        }
269
270        let delegation_in_free_ctx =
271            !#[allow(non_exhaustive_omitted_patterns)] match delegation_parent_kind {
    DefKind::Trait | DefKind::Impl { .. } => true,
    _ => false,
}matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. });
272
273        let sig_parent = self.tcx.parent(sig_id);
274        let sig_in_trait = #[allow(non_exhaustive_omitted_patterns)] match self.tcx.def_kind(sig_parent)
    {
    DefKind::Trait => true,
    _ => false,
}matches!(self.tcx.def_kind(sig_parent), DefKind::Trait);
275        let free_to_trait_delegation = delegation_in_free_ctx && sig_in_trait;
276        let generate_self = free_to_trait_delegation && is_method && delegation.qself.is_none();
277
278        let can_add_generics_to_parent = len >= 2
279            && self.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| {
280                #[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)
281            });
282
283        let parent_generics = if can_add_generics_to_parent {
284            let sig_parent_params = &self.tcx.generics_of(sig_parent).own_params[..];
285
286            if segments[len - 2].args.is_some() {
287                if generate_self {
288                    // Take only first Self parameter, it is trait so Self must be present.
289                    DelegationGenerics {
290                        kind: DelegationGenericsKind::SelfAndUserSpecified,
291                        generics: &sig_parent_params[..1],
292                        pos: GenericsPosition::Parent,
293                    }
294                } else {
295                    DelegationGenerics::user_specified(&[], GenericsPosition::Parent)
296                }
297            } else {
298                let skip_self = usize::from(!generate_self);
299                DelegationGenerics::default(
300                    &sig_parent_params[skip_self..],
301                    GenericsPosition::Parent,
302                )
303            }
304        } else {
305            DelegationGenerics::default(&[], GenericsPosition::Parent)
306        };
307
308        let child_generics = if child_user_specified {
309            let synth_params_index =
310                sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len());
311
312            DelegationGenerics::user_specified(
313                &sig_params[synth_params_index..],
314                GenericsPosition::Child,
315            )
316        } else {
317            DelegationGenerics::default(sig_params, GenericsPosition::Child)
318        };
319
320        GenericsGenerationResults {
321            parent: GenericsGenerationResult::new(parent_generics),
322            child: GenericsGenerationResult::new(child_generics),
323            self_ty_id: None,
324            propagate_self_ty: free_to_trait_delegation && !generate_self,
325        }
326    }
327
328    fn uplift_delegation_generic_params(
329        &mut self,
330        span: Span,
331        params: &'hir [ty::GenericParamDef],
332        rename_self: bool,
333    ) -> &'hir hir::Generics<'hir> {
334        let params = self.arena.alloc_from_iter(params.iter().map(|p| {
335            let def_kind = match p.kind {
336                GenericParamDefKind::Lifetime => DefKind::LifetimeParam,
337                GenericParamDefKind::Type { .. } => DefKind::TyParam,
338                GenericParamDefKind::Const { .. } => DefKind::ConstParam,
339            };
340
341            // Rename Self generic param to This so it is properly propagated.
342            // If the user will create a function `fn foo<Self>() {}` with generic
343            // param "Self" then it will not be generated in HIR, the same thing
344            // applies to traits, `trait Trait<Self> {}` will be represented as
345            // `trait Trait {}` in HIR and "unexpected keyword `Self` in generic parameters"
346            // error will be emitted.
347            // Note that we do not rename `Self` to `This` after non-recursive reuse
348            // from Trait, in this case the `Self` should not be propagated
349            // (we rely that implicit `Self` generic param of a trait is named "Self")
350            // and it is OK to have Self generic param generated during lowering.
351            let param_name =
352                if rename_self && p.name == kw::SelfUpper { sym::This } else { p.name };
353
354            let param_ident = Ident::new(param_name, span);
355            let def_name = Some(param_ident.name);
356            let node_id = self.next_node_id();
357
358            let def_id = self.create_def(node_id, def_name, def_kind, span);
359
360            let kind = match p.kind {
361                GenericParamDefKind::Lifetime => {
362                    hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
363                }
364                GenericParamDefKind::Type { synthetic, .. } => {
365                    hir::GenericParamKind::Type { default: None, synthetic }
366                }
367                GenericParamDefKind::Const { .. } => {
368                    let hir_id = self.next_id();
369                    let kind = hir::TyKind::InferDelegation(hir::InferDelegation::DefId(p.def_id));
370
371                    hir::GenericParamKind::Const {
372                        ty: self.arena.alloc(hir::Ty { kind, hir_id, span }),
373                        default: None,
374                    }
375                }
376            };
377
378            // Important: we don't use `self.next_id()` as we want to execute
379            // `lower_node_id` routine so param's id is added to `self.children`.
380            let hir_id = self.lower_node_id(node_id);
381
382            hir::GenericParam {
383                hir_id,
384                colon_span: Some(span),
385                def_id,
386                kind,
387                name: hir::ParamName::Plain(param_ident),
388                pure_wrt_drop: p.pure_wrt_drop,
389                source: hir::GenericParamSource::Generics,
390                span,
391            }
392        }));
393
394        // HACK: for now we generate predicates such that all lifetimes are early bound,
395        // we can not not generate early-bound lifetimes, but we can't know which of them
396        // are late-bound at this level of compilation.
397        let predicates =
398            self.arena.alloc_from_iter(params.iter().filter_map(|p| {
399                p.is_lifetime().then(|| self.generate_lifetime_predicate(p, span))
400            }));
401
402        self.arena.alloc(hir::Generics {
403            params,
404            predicates,
405            has_where_clause_predicates: false,
406            where_clause_span: span,
407            span,
408        })
409    }
410
411    fn generate_lifetime_predicate(
412        &mut self,
413        p: &hir::GenericParam<'hir>,
414        span: Span,
415    ) -> hir::WherePredicate<'hir> {
416        let create_lifetime = |this: &mut Self| -> &'hir hir::Lifetime {
417            this.arena.alloc(hir::Lifetime {
418                hir_id: this.next_id(),
419                ident: p.name.ident(),
420                kind: hir::LifetimeKind::Param(p.def_id),
421                source: hir::LifetimeSource::Path { angle_brackets: hir::AngleBrackets::Full },
422                syntax: hir::LifetimeSyntax::ExplicitBound,
423            })
424        };
425
426        hir::WherePredicate {
427            hir_id: self.next_id(),
428            span,
429            kind: self.arena.alloc(hir::WherePredicateKind::RegionPredicate(
430                hir::WhereRegionPredicate {
431                    in_where_clause: true,
432                    lifetime: create_lifetime(self),
433                    bounds: self
434                        .arena
435                        .alloc_slice(&[hir::GenericBound::Outlives(create_lifetime(self))]),
436                },
437            )),
438        }
439    }
440
441    fn create_generics_args_from_params(
442        &mut self,
443        params: &[hir::GenericParam<'hir>],
444        add_lifetimes: bool,
445        span: Span,
446    ) -> &'hir hir::GenericArgs<'hir> {
447        self.arena.alloc(hir::GenericArgs {
448            args: self.arena.alloc_from_iter(params.iter().filter_map(|p| {
449                // Skip self generic arg, we do not need to propagate it.
450                if p.name.ident().name == kw::SelfUpper || p.is_impl_trait() {
451                    return None;
452                }
453
454                let create_path = |this: &mut Self| {
455                    let res = Res::Def(
456                        match p.kind {
457                            hir::GenericParamKind::Lifetime { .. } => DefKind::LifetimeParam,
458                            hir::GenericParamKind::Type { .. } => DefKind::TyParam,
459                            hir::GenericParamKind::Const { .. } => DefKind::ConstParam,
460                        },
461                        p.def_id.to_def_id(),
462                    );
463
464                    hir::QPath::Resolved(
465                        None,
466                        self.arena.alloc(hir::Path {
467                            segments: this.arena.alloc_slice(&[hir::PathSegment {
468                                args: None,
469                                hir_id: this.next_id(),
470                                ident: p.name.ident(),
471                                infer_args: false,
472                                res,
473                            }]),
474                            res,
475                            span: p.span,
476                        }),
477                    )
478                };
479
480                match p.kind {
481                    hir::GenericParamKind::Lifetime { .. } => match add_lifetimes {
482                        true => Some(hir::GenericArg::Lifetime(self.arena.alloc(hir::Lifetime {
483                            hir_id: self.next_id(),
484                            ident: p.name.ident(),
485                            kind: hir::LifetimeKind::Param(p.def_id),
486                            source: hir::LifetimeSource::Path {
487                                angle_brackets: hir::AngleBrackets::Full,
488                            },
489                            syntax: hir::LifetimeSyntax::ExplicitBound,
490                        }))),
491                        false => None,
492                    },
493                    hir::GenericParamKind::Type { .. } => {
494                        Some(hir::GenericArg::Type(self.arena.alloc(hir::Ty {
495                            hir_id: self.next_id(),
496                            span: p.span,
497                            kind: hir::TyKind::Path(create_path(self)),
498                        })))
499                    }
500                    hir::GenericParamKind::Const { .. } => {
501                        Some(hir::GenericArg::Const(self.arena.alloc(hir::ConstArg {
502                            hir_id: self.next_id(),
503                            kind: hir::ConstArgKind::Path(create_path(self)),
504                            span: p.span,
505                        })))
506                    }
507                }
508            })),
509            constraints: &[],
510            parenthesized: hir::GenericArgsParentheses::No,
511            span_ext: span,
512        })
513    }
514}