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}