mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
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 rust-lang/rust#118212. r? @petrochenkov
This commit is contained in:
@@ -508,7 +508,7 @@ fn finalize_body_lowering(
|
||||
|
||||
// FIXME(fn_delegation): proper support for parent generics propagation
|
||||
// in method call scenario.
|
||||
let segment = self.process_segment(span, &segment, &mut generics.child, false);
|
||||
let segment = self.process_segment(span, &segment, &mut generics.child);
|
||||
let segment = self.arena.alloc(segment);
|
||||
|
||||
self.arena.alloc(hir::Expr {
|
||||
@@ -534,14 +534,10 @@ fn finalize_body_lowering(
|
||||
|
||||
new_path.segments = self.arena.alloc_from_iter(
|
||||
new_path.segments.iter().enumerate().map(|(idx, segment)| {
|
||||
let mut process_segment = |result, add_lifetimes| {
|
||||
self.process_segment(span, segment, result, add_lifetimes)
|
||||
};
|
||||
|
||||
if idx + 2 == len {
|
||||
process_segment(&mut generics.parent, true)
|
||||
self.process_segment(span, segment, &mut generics.parent)
|
||||
} else if idx + 1 == len {
|
||||
process_segment(&mut generics.child, false)
|
||||
self.process_segment(span, segment, &mut generics.child)
|
||||
} else {
|
||||
segment.clone()
|
||||
}
|
||||
@@ -551,7 +547,7 @@ fn finalize_body_lowering(
|
||||
hir::QPath::Resolved(ty, self.arena.alloc(new_path))
|
||||
}
|
||||
hir::QPath::TypeRelative(ty, segment) => {
|
||||
let segment = self.process_segment(span, segment, &mut generics.child, false);
|
||||
let segment = self.process_segment(span, segment, &mut generics.child);
|
||||
|
||||
hir::QPath::TypeRelative(ty, self.arena.alloc(segment))
|
||||
}
|
||||
@@ -584,13 +580,12 @@ fn process_segment(
|
||||
span: Span,
|
||||
segment: &hir::PathSegment<'hir>,
|
||||
result: &mut GenericsGenerationResult<'hir>,
|
||||
add_lifetimes: bool,
|
||||
) -> hir::PathSegment<'hir> {
|
||||
let details = result.generics.args_propagation_details();
|
||||
|
||||
let segment = if details.should_propagate {
|
||||
let generics = result.generics.into_hir_generics(self, span);
|
||||
let args = generics.into_generic_args(self, add_lifetimes, span);
|
||||
let args = generics.into_generic_args(self, span);
|
||||
|
||||
// Needed for better error messages (`trait-impl-wrong-args-count.rs` test).
|
||||
let args = if args.is_empty() { None } else { Some(args) };
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{Ident, Span};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
|
||||
use crate::{LoweringContext, ResolverAstLoweringExt};
|
||||
|
||||
@@ -25,22 +25,37 @@ pub(super) enum DelegationGenericsKind {
|
||||
TraitImpl(bool /* Has user-specified args */),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(super) enum GenericsPosition {
|
||||
Parent,
|
||||
Child,
|
||||
}
|
||||
|
||||
pub(super) struct DelegationGenerics<T> {
|
||||
generics: T,
|
||||
kind: DelegationGenericsKind,
|
||||
pos: GenericsPosition,
|
||||
}
|
||||
|
||||
impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> {
|
||||
fn default(generics: &'hir [ty::GenericParamDef]) -> Self {
|
||||
DelegationGenerics { generics, kind: DelegationGenericsKind::Default }
|
||||
fn default(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {
|
||||
DelegationGenerics { generics, pos, kind: DelegationGenericsKind::Default }
|
||||
}
|
||||
|
||||
fn user_specified(generics: &'hir [ty::GenericParamDef]) -> Self {
|
||||
DelegationGenerics { generics, kind: DelegationGenericsKind::UserSpecified }
|
||||
fn user_specified(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {
|
||||
DelegationGenerics { generics, pos, kind: DelegationGenericsKind::UserSpecified }
|
||||
}
|
||||
|
||||
fn trait_impl(generics: &'hir [ty::GenericParamDef], user_specified: bool) -> Self {
|
||||
DelegationGenerics { generics, kind: DelegationGenericsKind::TraitImpl(user_specified) }
|
||||
fn trait_impl(
|
||||
generics: &'hir [ty::GenericParamDef],
|
||||
user_specified: bool,
|
||||
pos: GenericsPosition,
|
||||
) -> Self {
|
||||
DelegationGenerics {
|
||||
generics,
|
||||
pos,
|
||||
kind: DelegationGenericsKind::TraitImpl(user_specified),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,8 +118,14 @@ pub(super) fn into_hir_generics(
|
||||
span: Span,
|
||||
) -> &mut HirOrTyGenerics<'hir> {
|
||||
if let HirOrTyGenerics::Ty(ty) = self {
|
||||
let params = ctx.uplift_delegation_generic_params(span, ty.generics);
|
||||
*self = HirOrTyGenerics::Hir(DelegationGenerics { generics: params, kind: ty.kind });
|
||||
let rename_self = matches!(ty.pos, GenericsPosition::Child);
|
||||
let params = ctx.uplift_delegation_generic_params(span, ty.generics, rename_self);
|
||||
|
||||
*self = HirOrTyGenerics::Hir(DelegationGenerics {
|
||||
generics: params,
|
||||
kind: ty.kind,
|
||||
pos: ty.pos,
|
||||
});
|
||||
}
|
||||
|
||||
self
|
||||
@@ -120,7 +141,6 @@ fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> {
|
||||
pub(super) fn into_generic_args(
|
||||
&self,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
add_lifetimes: bool,
|
||||
span: Span,
|
||||
) -> &'hir hir::GenericArgs<'hir> {
|
||||
match self {
|
||||
@@ -128,6 +148,7 @@ pub(super) fn into_generic_args(
|
||||
bug!("Attempting to get generic args before uplifting to HIR")
|
||||
}
|
||||
HirOrTyGenerics::Hir(hir) => {
|
||||
let add_lifetimes = matches!(hir.pos, GenericsPosition::Parent);
|
||||
ctx.create_generics_args_from_params(hir.generics.params, add_lifetimes, span)
|
||||
}
|
||||
}
|
||||
@@ -227,10 +248,15 @@ pub(super) fn uplift_delegation_generics(
|
||||
if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {
|
||||
// Considering parent generics, during signature inheritance
|
||||
// we will take those args that are in trait impl header trait ref.
|
||||
let parent = DelegationGenerics::trait_impl(&[], true);
|
||||
let parent = DelegationGenerics::trait_impl(&[], true, GenericsPosition::Parent);
|
||||
let parent = GenericsGenerationResult::new(parent);
|
||||
|
||||
let child = DelegationGenerics::trait_impl(sig_params, child_user_specified);
|
||||
let child = DelegationGenerics::trait_impl(
|
||||
sig_params,
|
||||
child_user_specified,
|
||||
GenericsPosition::Child,
|
||||
);
|
||||
|
||||
let child = GenericsGenerationResult::new(child);
|
||||
|
||||
return GenericsGenerationResults {
|
||||
@@ -263,25 +289,32 @@ pub(super) fn uplift_delegation_generics(
|
||||
DelegationGenerics {
|
||||
kind: DelegationGenericsKind::SelfAndUserSpecified,
|
||||
generics: &sig_parent_params[..1],
|
||||
pos: GenericsPosition::Parent,
|
||||
}
|
||||
} else {
|
||||
DelegationGenerics::user_specified(&[])
|
||||
DelegationGenerics::user_specified(&[], GenericsPosition::Parent)
|
||||
}
|
||||
} else {
|
||||
let skip_self = usize::from(!generate_self);
|
||||
DelegationGenerics::default(&sig_parent_params[skip_self..])
|
||||
DelegationGenerics::default(
|
||||
&sig_parent_params[skip_self..],
|
||||
GenericsPosition::Parent,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
DelegationGenerics::default(&[])
|
||||
DelegationGenerics::default(&[], GenericsPosition::Parent)
|
||||
};
|
||||
|
||||
let child_generics = if child_user_specified {
|
||||
let synth_params_index =
|
||||
sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len());
|
||||
|
||||
DelegationGenerics::user_specified(&sig_params[synth_params_index..])
|
||||
DelegationGenerics::user_specified(
|
||||
&sig_params[synth_params_index..],
|
||||
GenericsPosition::Child,
|
||||
)
|
||||
} else {
|
||||
DelegationGenerics::default(sig_params)
|
||||
DelegationGenerics::default(sig_params, GenericsPosition::Child)
|
||||
};
|
||||
|
||||
GenericsGenerationResults {
|
||||
@@ -296,6 +329,7 @@ fn uplift_delegation_generic_params(
|
||||
&mut self,
|
||||
span: Span,
|
||||
params: &'hir [ty::GenericParamDef],
|
||||
rename_self: bool,
|
||||
) -> &'hir hir::Generics<'hir> {
|
||||
let params = self.arena.alloc_from_iter(params.iter().map(|p| {
|
||||
let def_kind = match p.kind {
|
||||
@@ -304,7 +338,20 @@ fn uplift_delegation_generic_params(
|
||||
GenericParamDefKind::Const { .. } => DefKind::ConstParam,
|
||||
};
|
||||
|
||||
let param_ident = Ident::new(p.name, span);
|
||||
// Rename Self generic param to This so it is properly propagated.
|
||||
// If the user will create a function `fn foo<Self>() {}` with generic
|
||||
// param "Self" then it will not be generated in HIR, the same thing
|
||||
// applies to traits, `trait Trait<Self> {}` will be represented as
|
||||
// `trait Trait {}` in HIR and "unexpected keyword `Self` in generic parameters"
|
||||
// error will be emitted.
|
||||
// Note that we do not rename `Self` to `This` after non-recursive reuse
|
||||
// from Trait, in this case the `Self` should not be propagated
|
||||
// (we rely that implicit `Self` generic param of a trait is named "Self")
|
||||
// and it is OK to have Self generic param generated during lowering.
|
||||
let param_name =
|
||||
if rename_self && p.name == kw::SelfUpper { sym::This } else { p.name };
|
||||
|
||||
let param_ident = Ident::new(param_name, span);
|
||||
let def_name = Some(param_ident.name);
|
||||
let node_id = self.next_node_id();
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#![attr = Feature([fn_delegation#0])]
|
||||
extern crate std;
|
||||
#[attr = PreludeImport]
|
||||
use ::std::prelude::rust_2015::*;
|
||||
//@ pretty-compare-only
|
||||
//@ pretty-mode:hir
|
||||
//@ pp-exact:delegation-self-rename.pp
|
||||
|
||||
|
||||
trait Trait<'a, A, const B: bool> {
|
||||
fn foo<'b, const B2: bool, T, U,
|
||||
impl FnOnce() -> usize>(&self, f: impl FnOnce() -> usize) -> usize
|
||||
where impl FnOnce() -> usize: FnOnce() -> usize { f() + 1 }
|
||||
}
|
||||
|
||||
struct X;
|
||||
impl <'a, A, const B: bool> Trait<'a, A, B> for X { }
|
||||
|
||||
#[attr = Inline(Hint)]
|
||||
fn foo<'a, Self, A, const B: _, const B2: _, T, U,
|
||||
impl FnOnce() -> usize>(self: _, arg1: _) -> _ where
|
||||
'a:'a { self.foo::<B2, T, U>(arg1) }
|
||||
#[attr = Inline(Hint)]
|
||||
fn bar<Self, impl FnOnce() -> usize>(self: _, arg1: _)
|
||||
-> _ { Trait::<'static, (), true>::foo::<true, (), ()>(self, arg1) }
|
||||
|
||||
#[attr = Inline(Hint)]
|
||||
fn foo2<'a, This, A, const B: _, const B2: _, T, U,
|
||||
impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where
|
||||
'a:'a { foo::<This, A, B, B2, T, U>(arg0, arg1) }
|
||||
#[attr = Inline(Hint)]
|
||||
fn bar2<This, impl FnOnce() -> usize>(arg0: _, arg1: _)
|
||||
-> _ { bar::<This>(arg0, arg1) }
|
||||
|
||||
trait Trait2 {
|
||||
#[attr = Inline(Hint)]
|
||||
fn foo3<'a, This, A, const B: _, const B2: _, T, U,
|
||||
impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where
|
||||
'a:'a { foo2::<This, A, B, B2, T, U>(arg0, arg1) }
|
||||
#[attr = Inline(Hint)]
|
||||
fn bar3<This, impl FnOnce() -> usize>(arg0: _, arg1: _)
|
||||
-> _ { bar2::<This>(arg0, arg1) }
|
||||
}
|
||||
|
||||
impl Trait2 for () { }
|
||||
|
||||
#[attr = Inline(Hint)]
|
||||
fn foo4<'a, This, A, const B: _, const B2: _, T, U,
|
||||
impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where
|
||||
'a:'a { <() as Trait2>::foo3::<This, A, B, B2, T, U>(arg0, arg1) }
|
||||
#[attr = Inline(Hint)]
|
||||
fn bar4<This, impl FnOnce() -> usize>(arg0: _, arg1: _)
|
||||
-> _ { <() as Trait2>::bar3::<This>(arg0, arg1) }
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,32 @@
|
||||
//@ pretty-compare-only
|
||||
//@ pretty-mode:hir
|
||||
//@ pp-exact:delegation-self-rename.pp
|
||||
|
||||
#![feature(fn_delegation)]
|
||||
|
||||
trait Trait<'a, A, const B: bool> {
|
||||
fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize {
|
||||
f() + 1
|
||||
}
|
||||
}
|
||||
|
||||
struct X;
|
||||
impl<'a, A, const B: bool> Trait<'a, A, B> for X {}
|
||||
|
||||
reuse Trait::foo;
|
||||
reuse Trait::<'static, (), true>::foo::<true, (), ()> as bar;
|
||||
|
||||
reuse foo as foo2;
|
||||
reuse bar as bar2;
|
||||
|
||||
trait Trait2 {
|
||||
reuse foo2 as foo3;
|
||||
reuse bar2 as bar3;
|
||||
}
|
||||
|
||||
impl Trait2 for () {}
|
||||
|
||||
reuse <() as Trait2>::foo3 as foo4;
|
||||
reuse <() as Trait2>::bar3 as bar4;
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,45 @@
|
||||
//@ run-pass
|
||||
|
||||
#![feature(fn_delegation)]
|
||||
|
||||
trait Trait<'a, A, const B: bool> {
|
||||
fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize {
|
||||
f() + 1
|
||||
}
|
||||
}
|
||||
|
||||
struct X;
|
||||
impl<'a, A, const B: bool> Trait<'a, A, B> for X {}
|
||||
|
||||
reuse Trait::foo;
|
||||
reuse Trait::<'static, (), true>::foo::<true, (), ()> as bar;
|
||||
|
||||
reuse foo as foo2;
|
||||
reuse bar as bar2;
|
||||
|
||||
trait Trait2 {
|
||||
reuse foo2 as foo3;
|
||||
reuse bar2 as bar3;
|
||||
}
|
||||
|
||||
impl Trait2 for () {}
|
||||
|
||||
reuse <() as Trait2>::foo3 as foo4;
|
||||
reuse <() as Trait2>::bar3 as bar4;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 124);
|
||||
assert_eq!(foo2::<'static, X, (), true, false, (), ()>(&X, || 123), 124);
|
||||
assert_eq!(<()>::foo3::<'static, X, (), true, false, (), ()>(&X, || 123), 124);
|
||||
assert_eq!(foo4::<'static, X, (), true, false, (), ()>(&X, || 123), 124);
|
||||
|
||||
assert_eq!(bar::<X>(&X, || 123), 124);
|
||||
assert_eq!(bar2::<X>(&X, || 123), 124);
|
||||
assert_eq!(<()>::bar3::<X>(&X, || 123), 124);
|
||||
assert_eq!(bar4::<X>(&X, || 123), 124);
|
||||
|
||||
assert_eq!(bar(&X, || 123), 124);
|
||||
assert_eq!(bar2(&X, || 123), 124);
|
||||
assert_eq!(<()>::bar3(&X, || 123), 124);
|
||||
assert_eq!(bar4::<X>(&X, || 123), 124);
|
||||
}
|
||||
@@ -62,40 +62,49 @@ pub fn check() {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(fn_delegation): rename Self generic param in recursive delegations
|
||||
// mod test_4 {
|
||||
// trait Trait<'a, A, const B: bool> {
|
||||
// fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize {
|
||||
// f()
|
||||
// }
|
||||
// }
|
||||
// Test recursive delegation through trait
|
||||
mod test_4 {
|
||||
trait Trait<'a, A, const B: bool> {
|
||||
fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize {
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
// struct X;
|
||||
// impl<'a, A, const B: bool> Trait<'a, A, B> for X {}
|
||||
struct X;
|
||||
impl<'a, A, const B: bool> Trait<'a, A, B> for X {}
|
||||
|
||||
// reuse Trait::foo;
|
||||
// reuse Trait::<'static, (), true>::foo::<true, (), ()> as bar;
|
||||
reuse Trait::foo;
|
||||
reuse Trait::<'static, (), true>::foo::<true, (), ()> as bar;
|
||||
|
||||
// trait Trait2 {
|
||||
// reuse foo;
|
||||
// reuse bar;
|
||||
// }
|
||||
trait Trait2 {
|
||||
reuse foo;
|
||||
reuse bar;
|
||||
}
|
||||
|
||||
// reuse Trait2::foo as foo2;
|
||||
// reuse Trait2::foo::<'static, X, (), true, false, (), ()> as foo3;
|
||||
// reuse Trait2::bar as bar2;
|
||||
// reuse Trait2::bar::<X> as bar3;
|
||||
impl Trait2 for () {}
|
||||
|
||||
// pub fn check() {
|
||||
// assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 123);
|
||||
// assert_eq!(bar::<X>(&X, || 123), 123);
|
||||
// assert_eq!(bar(&X, || 123), 123);
|
||||
// }
|
||||
// }
|
||||
reuse <() as Trait2>::foo as foo2;
|
||||
reuse <() as Trait2>::foo::<'static, X, (), true, false, (), ()> as foo3;
|
||||
reuse <() as Trait2>::bar as bar2;
|
||||
reuse <() as Trait2>::bar::<X> as bar3;
|
||||
|
||||
pub fn check() {
|
||||
assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 123);
|
||||
assert_eq!(bar::<X>(&X, || 123), 123);
|
||||
assert_eq!(bar(&X, || 123), 123);
|
||||
|
||||
assert_eq!(foo2::<'static, X, (), true, false, (), ()>(&X, || 123), 123);
|
||||
assert_eq!(bar2::<X>(&X, || 123), 123);
|
||||
assert_eq!(bar2(&X, || 123), 123);
|
||||
|
||||
assert_eq!(foo3(&X, || 123), 123);
|
||||
assert_eq!(bar3(&X, || 123), 123);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_1::check();
|
||||
test_2::check();
|
||||
test_3::check();
|
||||
// test_4::check();
|
||||
test_4::check();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user