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