compiler/rustc_ast_lowering/src/delegation/generics.rs RUST 515 lines View on github.com → Search inside
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};1011use crate::LoweringContext;1213#[derive(Clone, 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 function24    /// in trait.25    TraitImpl(bool /* Has user-specified args */),26}2728#[derive(Debug, Clone, Copy)]29pub(super) enum GenericsPosition {30    Parent,31    Child,32}3334pub(super) struct DelegationGenerics<T> {35    generics: T,36    kind: DelegationGenericsKind,37    pos: GenericsPosition,38}3940impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> {41    fn default(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {42        DelegationGenerics { generics, pos, kind: DelegationGenericsKind::Default }43    }4445    fn user_specified(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {46        DelegationGenerics { generics, pos, kind: DelegationGenericsKind::UserSpecified }47    }4849    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}6162/// Used for storing either ty generics or their uplifted HIR version. First we obtain63/// ty generics. Next, at some point of generics processing we need to uplift those64/// generics to HIR, for this purpose we use `into_hir_generics` that uplifts ty generics65/// and replaces Ty variant with Hir. Such approach is useful as we can call this method66/// at any time knowing that uplifting will occur at most only once. Then, in order to obtain generic67/// 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 params70/// (i.e., method call scenarios), in such a case this approach helps71/// 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}7677pub(super) struct GenericsGenerationResult<'hir> {78    pub(super) generics: HirOrTyGenerics<'hir>,79    pub(super) args_segment_id: Option<HirId>,80}8182pub(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}8889pub(super) struct GenericArgsPropagationDetails {90    pub(super) should_propagate: bool,91    pub(super) use_args_in_sig_inheritance: bool,92}9394impl DelegationGenericsKind {95    fn args_propagation_details(self) -> GenericArgsPropagationDetails {96        match self {97            DelegationGenericsKind::UserSpecified98            | 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}113114impl<'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 = matches!(ty.pos, GenericsPosition::Child);122            let params = ctx.uplift_delegation_generic_params(span, ty.generics, rename_self);123124            *self = HirOrTyGenerics::Hir(DelegationGenerics {125                generics: params,126                kind: ty.kind,127                pos: ty.pos,128            });129        }130131        self132    }133134    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    }140141    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                bug!("Attempting to get generic args before uplifting to HIR")149            }150            HirOrTyGenerics::Hir(hir) => {151                let add_lifetimes = matches!(hir.pos, GenericsPosition::Parent);152                ctx.create_generics_args_from_params(hir.generics.params, add_lifetimes, span)153            }154        }155    }156157    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}164165impl<'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}172173impl<'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 like181        // method call will be supported (if HIR generics were not obtained182        // then it means that we did not propagated them, thus we do not need183        // to generate params).184        let mut create_params = |result: &mut GenericsGenerationResult<'hir>| {185            result.generics.into_hir_generics(ctx, span).hir_generics_or_empty().params186        };187188        let parent = create_params(&mut self.parent);189        let child = create_params(&mut self.child);190191        // 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        parent196            .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    }203204    /// 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 folding207    /// 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 like215        // method call will be supported (if HIR generics were not obtained216        // then it means that we did not propagated them, thus we do not need217        // to generate predicates).218        let mut create_predicates = |result: &mut GenericsGenerationResult<'hir>| {219            result.generics.into_hir_generics(ctx, span).hir_generics_or_empty().predicates220        };221222        let parent = create_predicates(&mut self.parent);223        let child = create_predicates(&mut self.child);224225        parent.into_iter().chain(child).copied()226    }227}228229impl<'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)));239240        let segments = &delegation.path.segments;241        let len = segments.len();242        let child_user_specified = segments[len - 1].args.is_some();243244        let sig_params = &self.tcx.generics_of(sig_id).own_params[..];245246        // If we are in trait impl always generate function whose generics matches247        // those that are defined in trait.248        if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {249            // Considering parent generics, during signature inheritance250            // 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);253254            let child = DelegationGenerics::trait_impl(255                sig_params,256                child_user_specified,257                GenericsPosition::Child,258            );259260            let child = GenericsGenerationResult::new(child);261262            return GenericsGenerationResults {263                parent,264                child,265                self_ty_id: None,266                propagate_self_ty: false,267            };268        }269270        let delegation_in_free_ctx =271            !matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. });272273        let sig_parent = self.tcx.parent(sig_id);274        let sig_in_trait = 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();277278        let can_add_generics_to_parent = len >= 2279            && self.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| {280                matches!(self.tcx.def_kind(def_id), DefKind::Trait | DefKind::TraitAlias)281            });282283        let parent_generics = if can_add_generics_to_parent {284            let sig_parent_params = &self.tcx.generics_of(sig_parent).own_params[..];285286            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        };307308        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());311312            DelegationGenerics::user_specified(313                &sig_params[synth_params_index..],314                GenericsPosition::Child,315            )316        } else {317            DelegationGenerics::default(sig_params, GenericsPosition::Child)318        };319320        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    }327328    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            };340341            // Rename Self generic param to This so it is properly propagated.342            // If the user will create a function `fn foo<Self>() {}` with generic343            // param "Self" then it will not be generated in HIR, the same thing344            // applies to traits, `trait Trait<Self> {}` will be represented as345            // `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 reuse348            // from Trait, in this case the `Self` should not be propagated349            // (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 };353354            let param_ident = Ident::new(param_name, span);355            let def_name = Some(param_ident.name);356            let node_id = self.next_node_id();357358            let def_id = self.create_def(node_id, def_name, def_kind, span);359360            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));370371                    hir::GenericParamKind::Const {372                        ty: self.arena.alloc(hir::Ty { kind, hir_id, span }),373                        default: None,374                    }375                }376            };377378            // Important: we don't use `self.next_id()` as we want to execute379            // `lower_node_id` routine so param's id is added to `self.children`.380            let hir_id = self.lower_node_id(node_id);381382            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        }));393394        // 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 them396        // 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            }));401402        self.arena.alloc(hir::Generics {403            params,404            predicates,405            has_where_clause_predicates: false,406            where_clause_span: span,407            span,408        })409    }410411    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        };425426        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: self434                        .arena435                        .alloc_slice(&[hir::GenericBound::Outlives(create_lifetime(self))]),436                },437            )),438        }439    }440441    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                }453454                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                    );463464                    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                };479480                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}

Code quality findings 16

Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
fn default(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
fn user_specified(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
generics: &'hir [ty::GenericParamDef],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
Ty(DelegationGenerics<&'hir [ty::GenericParamDef]>),
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
generics: DelegationGenerics<&'hir [ty::GenericParamDef]>,
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let child_user_specified = segments[len - 1].args.is_some();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let sig_params = &self.tcx.generics_of(sig_id).own_params[..];
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
&& self.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let sig_parent_params = &self.tcx.generics_of(sig_parent).own_params[..];
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
if segments[len - 2].args.is_some() {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
generics: &sig_parent_params[..1],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
&sig_parent_params[skip_self..],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
&sig_params[synth_params_index..],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
params: &'hir [ty::GenericParamDef],
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use rustc_ast::*;

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.