Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion compiler/rustc_ast_lowering/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {

let (param_count, c_variadic) = self.param_count(sig_id);

let mut generics = self.uplift_delegation_generics(delegation, sig_id, item_id);
let mut generics =
self.uplift_delegation_generics(delegation, sig_id, item_id, is_method);

let body_id = self.lower_delegation_body(
delegation,
Expand Down Expand Up @@ -301,6 +302,8 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
hir::InferDelegationSig::Output(self.arena.alloc(hir::DelegationGenerics {
child_args_segment_id: generics.child.args_segment_id,
parent_args_segment_id: generics.parent.args_segment_id,
self_ty_id: generics.self_ty_id,
propagate_self_ty: generics.propagate_self_ty,
})),
)),
span,
Expand Down Expand Up @@ -554,6 +557,12 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
}
};

generics.self_ty_id = match new_path {
hir::QPath::Resolved(ty, _) => ty,
hir::QPath::TypeRelative(ty, _) => Some(ty),
}
.map(|ty| ty.hir_id);

let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(new_path), span));
self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span))
};
Expand Down
15 changes: 13 additions & 2 deletions compiler/rustc_ast_lowering/src/delegation/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ pub(super) struct GenericsGenerationResult<'hir> {
pub(super) struct GenericsGenerationResults<'hir> {
pub(super) parent: GenericsGenerationResult<'hir>,
pub(super) child: GenericsGenerationResult<'hir>,
pub(super) self_ty_id: Option<HirId>,
pub(super) propagate_self_ty: bool,
}

pub(super) struct GenericArgsPropagationDetails {
Expand Down Expand Up @@ -209,6 +211,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
delegation: &Delegation,
sig_id: DefId,
item_id: NodeId,
is_method: bool,
) -> GenericsGenerationResults<'hir> {
let delegation_parent_kind =
self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id)));
Expand All @@ -230,21 +233,27 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
let child = DelegationGenerics::trait_impl(sig_params, child_user_specified);
let child = GenericsGenerationResult::new(child);

return GenericsGenerationResults { parent, child };
return GenericsGenerationResults {
parent,
child,
self_ty_id: None,
propagate_self_ty: false,
};
}

let delegation_in_free_ctx =
!matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. });

let sig_parent = self.tcx.parent(sig_id);
let sig_in_trait = matches!(self.tcx.def_kind(sig_parent), DefKind::Trait);
let free_to_trait_delegation = delegation_in_free_ctx && sig_in_trait;
let generate_self = free_to_trait_delegation && is_method && delegation.qself.is_none();

let can_add_generics_to_parent = len >= 2
&& self.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| {
matches!(self.tcx.def_kind(def_id), DefKind::Trait | DefKind::TraitAlias)
});

let generate_self = delegation_in_free_ctx && sig_in_trait;
let parent_generics = if can_add_generics_to_parent {
let sig_parent_params = &self.tcx.generics_of(sig_parent).own_params[..];

Expand Down Expand Up @@ -278,6 +287,8 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
GenericsGenerationResults {
parent: GenericsGenerationResult::new(parent_generics),
child: GenericsGenerationResult::new(child_generics),
self_ty_id: None,
propagate_self_ty: free_to_trait_delegation && !generate_self,
}
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3761,6 +3761,8 @@ pub enum OpaqueTyOrigin<D> {
pub struct DelegationGenerics {
pub parent_args_segment_id: Option<HirId>,
pub child_args_segment_id: Option<HirId>,
pub self_ty_id: Option<HirId>,
pub propagate_self_ty: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable_Generic)]
Expand Down
106 changes: 80 additions & 26 deletions compiler/rustc_hir_analysis/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::debug_assert_matches;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{HirId, PathSegment};
use rustc_hir::{DelegationGenerics, HirId, PathSegment};
use rustc_middle::ty::{
self, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
};
Expand Down Expand Up @@ -65,19 +65,35 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamIndexRemapper<'tcx> {
}

enum SelfPositionKind {
AfterLifetimes,
AfterLifetimes(bool /* Should propagate self ty */),
Zero,
None,
}

fn create_self_position_kind(caller_kind: FnKind, callee_kind: FnKind) -> SelfPositionKind {
match (caller_kind, callee_kind) {
fn get_delegation_generics(tcx: TyCtxt<'_>, delegation_id: LocalDefId) -> &DelegationGenerics {
tcx.hir_node(tcx.local_def_id_to_hir_id(delegation_id))
.fn_sig()
.expect("processing delegation")
.decl
.opt_delegation_generics()
.expect("processing delegation")
}

fn create_self_position_kind(
tcx: TyCtxt<'_>,
delegation_id: LocalDefId,
sig_id: DefId,
) -> SelfPositionKind {
match (fn_kind(tcx, delegation_id), fn_kind(tcx, sig_id)) {
(FnKind::AssocInherentImpl, FnKind::AssocTrait)
| (FnKind::AssocTraitImpl, FnKind::AssocTrait)
| (FnKind::AssocTrait, FnKind::AssocTrait)
| (FnKind::AssocTrait, FnKind::Free) => SelfPositionKind::Zero,

(FnKind::Free, FnKind::AssocTrait) => SelfPositionKind::AfterLifetimes,
(FnKind::Free, FnKind::AssocTrait) => {
let propagate_self_ty = get_delegation_generics(tcx, delegation_id).propagate_self_ty;
SelfPositionKind::AfterLifetimes(propagate_self_ty)
}

_ => SelfPositionKind::None,
}
Expand Down Expand Up @@ -141,8 +157,7 @@ fn create_mapping<'tcx>(
) -> FxHashMap<u32, u32> {
let mut mapping: FxHashMap<u32, u32> = Default::default();

let (caller_kind, callee_kind) = (fn_kind(tcx, def_id), fn_kind(tcx, sig_id));
let self_pos_kind = create_self_position_kind(caller_kind, callee_kind);
let self_pos_kind = create_self_position_kind(tcx, def_id, sig_id);
let is_self_at_zero = matches!(self_pos_kind, SelfPositionKind::Zero);

// Is self at zero? If so insert mapping, self in sig parent is always at 0.
Expand All @@ -156,7 +171,7 @@ fn create_mapping<'tcx>(
args_index += get_delegation_parent_args_count_without_self(tcx, def_id, sig_id);

let sig_generics = tcx.generics_of(sig_id);
let process_sig_parent_generics = matches!(callee_kind, FnKind::AssocTrait);
let process_sig_parent_generics = matches!(fn_kind(tcx, sig_id), FnKind::AssocTrait);

if process_sig_parent_generics {
for i in (sig_generics.has_self as usize)..sig_generics.parent_count {
Expand All @@ -176,7 +191,9 @@ fn create_mapping<'tcx>(
}

// If self after lifetimes insert mapping, relying that self is at 0 in sig parent.
if matches!(self_pos_kind, SelfPositionKind::AfterLifetimes) {
// If self ty is propagated (meaning there is no generic param `Self`), the specified
// self ty will be inserted in args in `create_generic_args`.
if matches!(self_pos_kind, SelfPositionKind::AfterLifetimes { .. }) {
mapping.insert(0, args_index as u32);
args_index += 1;
}
Expand Down Expand Up @@ -259,6 +276,22 @@ fn get_parent_and_inheritance_kind<'tcx>(
}
}

fn get_delegation_self_ty_or_err(tcx: TyCtxt<'_>, delegation_id: LocalDefId) -> Ty<'_> {
get_delegation_generics(tcx, delegation_id)
.self_ty_id
.map(|id| {
let ctx = ItemCtxt::new(tcx, delegation_id);
ctx.lower_ty(tcx.hir_node(id).expect_ty())
})
.unwrap_or_else(|| {
Ty::new_error_with_message(
tcx,
tcx.def_span(delegation_id),
"the self type must be specified",
)
})
}

fn get_delegation_self_ty<'tcx>(tcx: TyCtxt<'tcx>, delegation_id: LocalDefId) -> Option<Ty<'tcx>> {
let sig_id = tcx.hir_opt_delegation_sig_id(delegation_id).expect("Delegation must have sig_id");
let (caller_kind, callee_kind) = (fn_kind(tcx, delegation_id), fn_kind(tcx, sig_id));
Expand All @@ -269,15 +302,19 @@ fn get_delegation_self_ty<'tcx>(tcx: TyCtxt<'tcx>, delegation_id: LocalDefId) ->
| (FnKind::Free, FnKind::Free)
| (FnKind::AssocTrait, FnKind::Free)
| (FnKind::AssocTrait, FnKind::AssocTrait) => {
match create_self_position_kind(caller_kind, callee_kind) {
match create_self_position_kind(tcx, delegation_id, sig_id) {
SelfPositionKind::None => None,
SelfPositionKind::AfterLifetimes => {
// Both sig parent and child lifetimes are in included in this count.
Some(tcx.generics_of(delegation_id).own_counts().lifetimes)
SelfPositionKind::AfterLifetimes(propagate_self_ty) => {
if propagate_self_ty {
Some(get_delegation_self_ty_or_err(tcx, delegation_id))
} else {
// Both sig parent and child lifetimes are in included in this count.
let index = tcx.generics_of(delegation_id).own_counts().lifetimes;
Some(Ty::new_param(tcx, index as u32, kw::SelfUpper))
}
}
SelfPositionKind::Zero => Some(0),
SelfPositionKind::Zero => Some(Ty::new_param(tcx, 0, kw::SelfUpper)),
}
.map(|self_index| Ty::new_param(tcx, self_index as u32, kw::SelfUpper))
}

(FnKind::AssocTraitImpl, FnKind::AssocTrait)
Expand Down Expand Up @@ -366,15 +403,15 @@ fn create_generic_args<'tcx>(

let mut new_args = vec![];

let self_pos_kind = create_self_position_kind(caller_kind, callee_kind);
let self_pos_kind = create_self_position_kind(tcx, delegation_id, sig_id);
let mut lifetimes_end_pos;

if !parent_args.is_empty() {
let parent_args_lifetimes_count =
parent_args.iter().filter(|a| a.as_region().is_some()).count();

match self_pos_kind {
SelfPositionKind::AfterLifetimes => {
SelfPositionKind::AfterLifetimes { .. } => {
new_args.extend(&parent_args[1..1 + parent_args_lifetimes_count]);

lifetimes_end_pos = parent_args_lifetimes_count;
Expand Down Expand Up @@ -407,6 +444,15 @@ fn create_generic_args<'tcx>(
.count();

new_args.extend_from_slice(args);

// Parent args are empty, then if we should propagate self ty (meaning Self generic
// param was not generated) then we should insert it, as it won't be in `args`.
if matches!(self_pos_kind, SelfPositionKind::AfterLifetimes(true)) {
new_args.insert(
lifetimes_end_pos,
ty::GenericArg::from(get_delegation_self_ty_or_err(tcx, delegation_id)),
);
}
}

if !child_args.is_empty() {
Expand All @@ -427,7 +473,8 @@ fn create_generic_args<'tcx>(
new_args.insert(lifetimes_end_pos + i, child_args[i]);
}

let skip_self = matches!(self_pos_kind, SelfPositionKind::AfterLifetimes);
// If self_ty is propagated it means that Self generic param was not generated.
let skip_self = matches!(self_pos_kind, SelfPositionKind::AfterLifetimes(false));
new_args.extend(&child_args[child_lifetimes_count + skip_self as usize..]);
}

Expand All @@ -446,6 +493,7 @@ pub(crate) fn inherit_predicates_for_delegation_item<'tcx>(
preds: Vec<(ty::Clause<'tcx>, Span)>,
args: Vec<ty::GenericArg<'tcx>>,
folder: ParamIndexRemapper<'tcx>,
filter_self_preds: bool,
}

impl<'tcx> PredicatesCollector<'tcx> {
Expand All @@ -458,6 +506,16 @@ pub(crate) fn inherit_predicates_for_delegation_item<'tcx>(
let args = self.args.as_slice();

for pred in preds.predicates {
// If self ty is specified then there will be no generic param `Self`,
// so we do not need its predicates.
if self.filter_self_preds
&& let Some(trait_pred) = pred.0.as_trait_clause()
// Rely that `Self` has zero index.
&& trait_pred.self_ty().skip_binder().is_param(0)
{
continue;
}

let new_pred = pred.0.fold_with(&mut self.folder);
self.preds.push((
EarlyBinder::bind(new_pred).instantiate(self.tcx, args).skip_norm_wip(),
Expand All @@ -484,8 +542,10 @@ pub(crate) fn inherit_predicates_for_delegation_item<'tcx>(

let (parent_args, child_args) = get_delegation_user_specified_args(tcx, def_id);
let (folder, args) = create_folder_and_args(tcx, def_id, sig_id, parent_args, child_args);
let collector = PredicatesCollector { tcx, preds: vec![], args, folder };
let self_pos_kind = create_self_position_kind(tcx, def_id, sig_id);
let filter_self_preds = matches!(self_pos_kind, SelfPositionKind::AfterLifetimes(true));

let collector = PredicatesCollector { tcx, preds: vec![], args, folder, filter_self_preds };
let (parent, inh_kind) = get_parent_and_inheritance_kind(tcx, def_id, sig_id);

// `explicit_predicates_of` is used here to avoid copying `Self: Trait` predicate.
Expand Down Expand Up @@ -573,13 +633,7 @@ fn get_delegation_user_specified_args<'tcx>(
tcx: TyCtxt<'tcx>,
delegation_id: LocalDefId,
) -> (&'tcx [ty::GenericArg<'tcx>], &'tcx [ty::GenericArg<'tcx>]) {
let info = tcx
.hir_node(tcx.local_def_id_to_hir_id(delegation_id))
.fn_sig()
.expect("Lowering delegation")
.decl
.opt_delegation_generics()
.expect("Lowering delegation");
let info = get_delegation_generics(tcx, delegation_id);

let get_segment = |hir_id: HirId| -> Option<(&'tcx PathSegment<'tcx>, DefId)> {
let segment = tcx.hir_node(hir_id).expect_path_segment();
Expand Down
4 changes: 2 additions & 2 deletions tests/pretty/delegation-inherit-attributes.pp
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@

#[attr = MustUse {reason: "some reason"}]
#[attr = Inline(Hint)]
fn foo<Self>(self: _, arg1: _) -> _ { <X as T>::foo(self + 1, arg1) }
fn foo(self: _, arg1: _) -> _ { <X as T>::foo(self + 1, arg1) }
#[attr = MustUse {reason: "some reason"}]
#[attr = Inline(Hint)]
fn bar<Self>(arg0: _, arg1: _) -> _ { foo(self + 1, arg1) }
fn bar(arg0: _, arg1: _) -> _ { foo(self + 1, arg1) }
}
}

Expand Down
1 change: 0 additions & 1 deletion tests/ui/delegation/auxiliary/recursive-delegation-aux.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]

fn foo() {}

Expand Down
1 change: 0 additions & 1 deletion tests/ui/delegation/bad-resolve.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]

trait Trait {
const C: u32 = 0;
Expand Down
Loading
Loading