Skip to content

Commit ef162a5

Browse files
Rollup merge of #155635 - aerooneqq:delegation-generics-Self-rename, r=petrochenkov
delegation: rename `Self` generic param to `This` in recursive delegations This PR supports renaming of `Self` generic parameter to `This` in recursive delegations scenario, this allows propagation of `This` as we rely on `Self` naming to check whether it is implicit Self of a trait. Comment with a bit deeper explanation is in `uplift_delegation_generic_params`. Part of #118212. r? @petrochenkov
2 parents e873839 + 7f2a98d commit ef162a5

6 files changed

Lines changed: 242 additions & 59 deletions

File tree

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
508508

509509
// FIXME(fn_delegation): proper support for parent generics propagation
510510
// in method call scenario.
511-
let segment = self.process_segment(span, &segment, &mut generics.child, false);
511+
let segment = self.process_segment(span, &segment, &mut generics.child);
512512
let segment = self.arena.alloc(segment);
513513

514514
self.arena.alloc(hir::Expr {
@@ -534,14 +534,10 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
534534

535535
new_path.segments = self.arena.alloc_from_iter(
536536
new_path.segments.iter().enumerate().map(|(idx, segment)| {
537-
let mut process_segment = |result, add_lifetimes| {
538-
self.process_segment(span, segment, result, add_lifetimes)
539-
};
540-
541537
if idx + 2 == len {
542-
process_segment(&mut generics.parent, true)
538+
self.process_segment(span, segment, &mut generics.parent)
543539
} else if idx + 1 == len {
544-
process_segment(&mut generics.child, false)
540+
self.process_segment(span, segment, &mut generics.child)
545541
} else {
546542
segment.clone()
547543
}
@@ -551,7 +547,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
551547
hir::QPath::Resolved(ty, self.arena.alloc(new_path))
552548
}
553549
hir::QPath::TypeRelative(ty, segment) => {
554-
let segment = self.process_segment(span, segment, &mut generics.child, false);
550+
let segment = self.process_segment(span, segment, &mut generics.child);
555551

556552
hir::QPath::TypeRelative(ty, self.arena.alloc(segment))
557553
}
@@ -584,13 +580,12 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
584580
span: Span,
585581
segment: &hir::PathSegment<'hir>,
586582
result: &mut GenericsGenerationResult<'hir>,
587-
add_lifetimes: bool,
588583
) -> hir::PathSegment<'hir> {
589584
let details = result.generics.args_propagation_details();
590585

591586
let segment = if details.should_propagate {
592587
let generics = result.generics.into_hir_generics(self, span);
593-
let args = generics.into_generic_args(self, add_lifetimes, span);
588+
let args = generics.into_generic_args(self, span);
594589

595590
// Needed for better error messages (`trait-impl-wrong-args-count.rs` test).
596591
let args = if args.is_empty() { None } else { Some(args) };

compiler/rustc_ast_lowering/src/delegation/generics.rs

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId;
66
use rustc_middle::ty::GenericParamDefKind;
77
use rustc_middle::{bug, ty};
88
use rustc_span::symbol::kw;
9-
use rustc_span::{Ident, Span};
9+
use rustc_span::{Ident, Span, sym};
1010

1111
use crate::{LoweringContext, ResolverAstLoweringExt};
1212

@@ -25,22 +25,37 @@ pub(super) enum DelegationGenericsKind {
2525
TraitImpl(bool /* Has user-specified args */),
2626
}
2727

28+
#[derive(Debug, Clone, Copy)]
29+
pub(super) enum GenericsPosition {
30+
Parent,
31+
Child,
32+
}
33+
2834
pub(super) struct DelegationGenerics<T> {
2935
generics: T,
3036
kind: DelegationGenericsKind,
37+
pos: GenericsPosition,
3138
}
3239

3340
impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> {
34-
fn default(generics: &'hir [ty::GenericParamDef]) -> Self {
35-
DelegationGenerics { generics, kind: DelegationGenericsKind::Default }
41+
fn default(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {
42+
DelegationGenerics { generics, pos, kind: DelegationGenericsKind::Default }
3643
}
3744

38-
fn user_specified(generics: &'hir [ty::GenericParamDef]) -> Self {
39-
DelegationGenerics { generics, kind: DelegationGenericsKind::UserSpecified }
45+
fn user_specified(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {
46+
DelegationGenerics { generics, pos, kind: DelegationGenericsKind::UserSpecified }
4047
}
4148

42-
fn trait_impl(generics: &'hir [ty::GenericParamDef], user_specified: bool) -> Self {
43-
DelegationGenerics { generics, kind: DelegationGenericsKind::TraitImpl(user_specified) }
49+
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+
}
4459
}
4560
}
4661

@@ -103,8 +118,14 @@ impl<'hir> HirOrTyGenerics<'hir> {
103118
span: Span,
104119
) -> &mut HirOrTyGenerics<'hir> {
105120
if let HirOrTyGenerics::Ty(ty) = self {
106-
let params = ctx.uplift_delegation_generic_params(span, ty.generics);
107-
*self = HirOrTyGenerics::Hir(DelegationGenerics { generics: params, kind: ty.kind });
121+
let rename_self = matches!(ty.pos, GenericsPosition::Child);
122+
let params = ctx.uplift_delegation_generic_params(span, ty.generics, rename_self);
123+
124+
*self = HirOrTyGenerics::Hir(DelegationGenerics {
125+
generics: params,
126+
kind: ty.kind,
127+
pos: ty.pos,
128+
});
108129
}
109130

110131
self
@@ -120,14 +141,14 @@ impl<'hir> HirOrTyGenerics<'hir> {
120141
pub(super) fn into_generic_args(
121142
&self,
122143
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
123-
add_lifetimes: bool,
124144
span: Span,
125145
) -> &'hir hir::GenericArgs<'hir> {
126146
match self {
127147
HirOrTyGenerics::Ty(_) => {
128148
bug!("Attempting to get generic args before uplifting to HIR")
129149
}
130150
HirOrTyGenerics::Hir(hir) => {
151+
let add_lifetimes = matches!(hir.pos, GenericsPosition::Parent);
131152
ctx.create_generics_args_from_params(hir.generics.params, add_lifetimes, span)
132153
}
133154
}
@@ -227,10 +248,15 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
227248
if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {
228249
// Considering parent generics, during signature inheritance
229250
// we will take those args that are in trait impl header trait ref.
230-
let parent = DelegationGenerics::trait_impl(&[], true);
251+
let parent = DelegationGenerics::trait_impl(&[], true, GenericsPosition::Parent);
231252
let parent = GenericsGenerationResult::new(parent);
232253

233-
let child = DelegationGenerics::trait_impl(sig_params, child_user_specified);
254+
let child = DelegationGenerics::trait_impl(
255+
sig_params,
256+
child_user_specified,
257+
GenericsPosition::Child,
258+
);
259+
234260
let child = GenericsGenerationResult::new(child);
235261

236262
return GenericsGenerationResults {
@@ -263,25 +289,32 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
263289
DelegationGenerics {
264290
kind: DelegationGenericsKind::SelfAndUserSpecified,
265291
generics: &sig_parent_params[..1],
292+
pos: GenericsPosition::Parent,
266293
}
267294
} else {
268-
DelegationGenerics::user_specified(&[])
295+
DelegationGenerics::user_specified(&[], GenericsPosition::Parent)
269296
}
270297
} else {
271298
let skip_self = usize::from(!generate_self);
272-
DelegationGenerics::default(&sig_parent_params[skip_self..])
299+
DelegationGenerics::default(
300+
&sig_parent_params[skip_self..],
301+
GenericsPosition::Parent,
302+
)
273303
}
274304
} else {
275-
DelegationGenerics::default(&[])
305+
DelegationGenerics::default(&[], GenericsPosition::Parent)
276306
};
277307

278308
let child_generics = if child_user_specified {
279309
let synth_params_index =
280310
sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len());
281311

282-
DelegationGenerics::user_specified(&sig_params[synth_params_index..])
312+
DelegationGenerics::user_specified(
313+
&sig_params[synth_params_index..],
314+
GenericsPosition::Child,
315+
)
283316
} else {
284-
DelegationGenerics::default(sig_params)
317+
DelegationGenerics::default(sig_params, GenericsPosition::Child)
285318
};
286319

287320
GenericsGenerationResults {
@@ -296,6 +329,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
296329
&mut self,
297330
span: Span,
298331
params: &'hir [ty::GenericParamDef],
332+
rename_self: bool,
299333
) -> &'hir hir::Generics<'hir> {
300334
let params = self.arena.alloc_from_iter(params.iter().map(|p| {
301335
let def_kind = match p.kind {
@@ -304,7 +338,20 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
304338
GenericParamDefKind::Const { .. } => DefKind::ConstParam,
305339
};
306340

307-
let param_ident = Ident::new(p.name, span);
341+
// Rename Self generic param to This so it is properly propagated.
342+
// If the user will create a function `fn foo<Self>() {}` with generic
343+
// param "Self" then it will not be generated in HIR, the same thing
344+
// applies to traits, `trait Trait<Self> {}` will be represented as
345+
// `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 reuse
348+
// from Trait, in this case the `Self` should not be propagated
349+
// (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 };
353+
354+
let param_ident = Ident::new(param_name, span);
308355
let def_name = Some(param_ident.name);
309356
let node_id = self.next_node_id();
310357

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#![attr = Feature([fn_delegation#0])]
2+
extern crate std;
3+
#[attr = PreludeImport]
4+
use ::std::prelude::rust_2015::*;
5+
//@ pretty-compare-only
6+
//@ pretty-mode:hir
7+
//@ pp-exact:delegation-self-rename.pp
8+
9+
10+
trait Trait<'a, A, const B: bool> {
11+
fn foo<'b, const B2: bool, T, U,
12+
impl FnOnce() -> usize>(&self, f: impl FnOnce() -> usize) -> usize
13+
where impl FnOnce() -> usize: FnOnce() -> usize { f() + 1 }
14+
}
15+
16+
struct X;
17+
impl <'a, A, const B: bool> Trait<'a, A, B> for X { }
18+
19+
#[attr = Inline(Hint)]
20+
fn foo<'a, Self, A, const B: _, const B2: _, T, U,
21+
impl FnOnce() -> usize>(self: _, arg1: _) -> _ where
22+
'a:'a { self.foo::<B2, T, U>(arg1) }
23+
#[attr = Inline(Hint)]
24+
fn bar<Self, impl FnOnce() -> usize>(self: _, arg1: _)
25+
-> _ { Trait::<'static, (), true>::foo::<true, (), ()>(self, arg1) }
26+
27+
#[attr = Inline(Hint)]
28+
fn foo2<'a, This, A, const B: _, const B2: _, T, U,
29+
impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where
30+
'a:'a { foo::<This, A, B, B2, T, U>(arg0, arg1) }
31+
#[attr = Inline(Hint)]
32+
fn bar2<This, impl FnOnce() -> usize>(arg0: _, arg1: _)
33+
-> _ { bar::<This>(arg0, arg1) }
34+
35+
trait Trait2 {
36+
#[attr = Inline(Hint)]
37+
fn foo3<'a, This, A, const B: _, const B2: _, T, U,
38+
impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where
39+
'a:'a { foo2::<This, A, B, B2, T, U>(arg0, arg1) }
40+
#[attr = Inline(Hint)]
41+
fn bar3<This, impl FnOnce() -> usize>(arg0: _, arg1: _)
42+
-> _ { bar2::<This>(arg0, arg1) }
43+
}
44+
45+
impl Trait2 for () { }
46+
47+
#[attr = Inline(Hint)]
48+
fn foo4<'a, This, A, const B: _, const B2: _, T, U,
49+
impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where
50+
'a:'a { <() as Trait2>::foo3::<This, A, B, B2, T, U>(arg0, arg1) }
51+
#[attr = Inline(Hint)]
52+
fn bar4<This, impl FnOnce() -> usize>(arg0: _, arg1: _)
53+
-> _ { <() as Trait2>::bar3::<This>(arg0, arg1) }
54+
55+
fn main() { }
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ pretty-compare-only
2+
//@ pretty-mode:hir
3+
//@ pp-exact:delegation-self-rename.pp
4+
5+
#![feature(fn_delegation)]
6+
7+
trait Trait<'a, A, const B: bool> {
8+
fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize {
9+
f() + 1
10+
}
11+
}
12+
13+
struct X;
14+
impl<'a, A, const B: bool> Trait<'a, A, B> for X {}
15+
16+
reuse Trait::foo;
17+
reuse Trait::<'static, (), true>::foo::<true, (), ()> as bar;
18+
19+
reuse foo as foo2;
20+
reuse bar as bar2;
21+
22+
trait Trait2 {
23+
reuse foo2 as foo3;
24+
reuse bar2 as bar3;
25+
}
26+
27+
impl Trait2 for () {}
28+
29+
reuse <() as Trait2>::foo3 as foo4;
30+
reuse <() as Trait2>::bar3 as bar4;
31+
32+
fn main() {}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//@ run-pass
2+
3+
#![feature(fn_delegation)]
4+
5+
trait Trait<'a, A, const B: bool> {
6+
fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize {
7+
f() + 1
8+
}
9+
}
10+
11+
struct X;
12+
impl<'a, A, const B: bool> Trait<'a, A, B> for X {}
13+
14+
reuse Trait::foo;
15+
reuse Trait::<'static, (), true>::foo::<true, (), ()> as bar;
16+
17+
reuse foo as foo2;
18+
reuse bar as bar2;
19+
20+
trait Trait2 {
21+
reuse foo2 as foo3;
22+
reuse bar2 as bar3;
23+
}
24+
25+
impl Trait2 for () {}
26+
27+
reuse <() as Trait2>::foo3 as foo4;
28+
reuse <() as Trait2>::bar3 as bar4;
29+
30+
fn main() {
31+
assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 124);
32+
assert_eq!(foo2::<'static, X, (), true, false, (), ()>(&X, || 123), 124);
33+
assert_eq!(<()>::foo3::<'static, X, (), true, false, (), ()>(&X, || 123), 124);
34+
assert_eq!(foo4::<'static, X, (), true, false, (), ()>(&X, || 123), 124);
35+
36+
assert_eq!(bar::<X>(&X, || 123), 124);
37+
assert_eq!(bar2::<X>(&X, || 123), 124);
38+
assert_eq!(<()>::bar3::<X>(&X, || 123), 124);
39+
assert_eq!(bar4::<X>(&X, || 123), 124);
40+
41+
assert_eq!(bar(&X, || 123), 124);
42+
assert_eq!(bar2(&X, || 123), 124);
43+
assert_eq!(<()>::bar3(&X, || 123), 124);
44+
assert_eq!(bar4::<X>(&X, || 123), 124);
45+
}

0 commit comments

Comments
 (0)