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