Skip to content

Commit 85171bc

Browse files
committed
Always use associated type bound
1 parent f4e70bd commit 85171bc

File tree

7 files changed

+51
-222
lines changed

7 files changed

+51
-222
lines changed

prdoc/pr_7229.prdoc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
22
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
33

4-
title: "FRAME: Remove `RuntimeEvent` associated type from `Config` trait"
4+
title: "FRAME: Deprecate `RuntimeEvent` associated type from `Config` trait"
55
doc:
66
- audience: Runtime Dev
77
description: |
@@ -25,12 +25,12 @@ doc:
2525
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
2626
}
2727
```
28-
29-
Or if developers want to explicitly define the `RuntimeEvent` type bound, they can still do so.
28+
The latter compiles but is redundant since the associated type bound is automatically appended
29+
if pallet defines `Event` type, i.e it looks like this after macro expansion:
3030

3131
```rs
3232
#[pallet::config]
33-
pub trait Config: frame_system::Config<RuntimeEvent: From<Event<Self>>> {
33+
pub trait Config: frame_system::Config + frame_system::Config<RuntimeEvent: From<Event<Self>>> {
3434
}
3535
```
3636

substrate/frame/support/procedural/src/pallet/expand/config.rs

Lines changed: 22 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
// See the License for the specific language governing permissions and
1616
// limitations under the License.
1717

18-
use crate::pallet::{parse::config::has_expected_system_config, Def};
18+
use crate::pallet::{parse::GenericKind, Def};
1919
use proc_macro2::TokenStream;
20-
use quote::{quote, ToTokens};
21-
use syn::{parse_quote, Item, PathArguments, TypeParamBound};
20+
use quote::quote;
21+
use syn::{parse_quote, Item};
2222

2323
///
2424
/// * Generate default rust doc
@@ -50,34 +50,25 @@ Consequently, a runtime that wants to include this pallet must implement this tr
5050

5151
// insert `frame_system::Config` supertrait with `RuntimeEvent: From<Event<Self>>` if neither
5252
// associated type nor type bound is defined.
53-
if def.event.is_some() && !config.has_event_type && !config.has_event_bound {
54-
// find the `frame_system::Config` supertrait
55-
let frame_system = crate::generate_access_from_frame_or_crate("frame-system")
56-
.expect("should have access to frame-system");
57-
58-
if let Some(TypeParamBound::Trait(trait_bound)) =
59-
config_item.supertraits.iter_mut().find(|s| {
60-
syn::parse2::<syn::Path>(s.to_token_stream())
61-
.map_or(false, |b| has_expected_system_config(b, &frame_system))
62-
}) {
63-
let event_bound: syn::GenericArgument = parse_quote!(RuntimeEvent: From<Event<Self>>);
64-
65-
if let Some(segment) =
66-
trait_bound.path.segments.iter_mut().find(|s| s.ident == "Config")
67-
{
68-
match &mut segment.arguments {
69-
// when `Config<SomeType: Bound`
70-
syn::PathArguments::AngleBracketed(args) => {
71-
args.args.push(event_bound);
72-
},
73-
// when `Config`
74-
syn::PathArguments::None => {
75-
segment.arguments =
76-
PathArguments::AngleBracketed(parse_quote!(<#event_bound>));
77-
},
78-
_ => unreachable!("Checked by has_expected_system_config"),
79-
}
80-
}
53+
if let Some(event) = &def.event {
54+
if !def.is_frame_system {
55+
let frame_system = crate::generate_access_from_frame_or_crate("frame-system")
56+
.expect("should have access to frame-system");
57+
58+
// can't use `type_use_gen()` since it returns `T`, not `Self`
59+
let event_use_gen = match event.gen_kind {
60+
GenericKind::None => quote!(),
61+
GenericKind::Config => quote::quote_spanned! {event.attr_span => Self},
62+
GenericKind::ConfigAndInstance =>
63+
quote::quote_spanned! {event.attr_span => Self, I},
64+
};
65+
66+
let supertrait_with_event_bound = syn::parse2::<syn::TypeParamBound>(
67+
quote! { #frame_system::Config<RuntimeEvent: From<Event<#event_use_gen>>> },
68+
)
69+
.expect("should be possible to parse system supertrait");
70+
71+
config_item.supertraits.push(supertrait_with_event_bound.into());
8172
}
8273
}
8374

@@ -177,14 +168,3 @@ pub fn expand_config_metadata(def: &Def) -> proc_macro2::TokenStream {
177168
}
178169
)
179170
}
180-
181-
#[test]
182-
fn test_parse_quote() {
183-
// pub trait Config: pallet_balances::Config + frame_system::Config<RuntimeEvent:
184-
// From<Event<Self>>>{
185-
186-
// the `RuntimeEvent: From<Event<Self>>` part
187-
let event: syn::AngleBracketedGenericArguments = parse_quote!(RuntimeEvent: From<Event<Self>>);
188-
let event_bound = syn::parse2::<syn::PathSegment>(event.to_token_stream()).unwrap();
189-
println!("{:?}", event_bound);
190-
}

substrate/frame/support/procedural/src/pallet/expand/event.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -136,32 +136,23 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream {
136136

137137
let deposit_event = if let Some(deposit_event) = &event.deposit_event {
138138
let event_use_gen = &event.gen_kind.type_use_gen(event.attr_span);
139-
let trait_use_gen = &def.trait_use_generics(event.attr_span);
140139
let type_impl_gen = &def.type_impl_generics(event.attr_span);
141140
let type_use_gen = &def.type_use_generics(event.attr_span);
142141
let pallet_ident = &def.pallet_struct.pallet;
143142

144143
let PalletEventDepositAttr { fn_vis, fn_span, .. } = deposit_event;
145144

146-
// `RuntimeEvent` can be defined either as associated type in `Config` or as a type bound in
147-
// system supertrait.
148-
let runtime_event_path = if def.config.has_event_bound || !def.config.has_event_type {
149-
quote::quote! { <T as #frame_system::Config>::RuntimeEvent }
150-
} else {
151-
quote::quote! { <T as Config #trait_use_gen>::RuntimeEvent }
152-
};
153-
154145
quote::quote_spanned!(*fn_span =>
155146
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
156147
#fn_vis fn deposit_event(event: Event<#event_use_gen>) {
157148
let event = <
158-
#runtime_event_path as
149+
<T as #frame_system::Config>::RuntimeEvent as
159150
From<Event<#event_use_gen>>
160151
>::from(event);
161152

162153
let event = <
163-
#runtime_event_path as
164-
Into<#runtime_event_path>
154+
<T as #frame_system::Config>::RuntimeEvent as
155+
Into<<T as #frame_system::Config>::RuntimeEvent>
165156
>::into(event);
166157

167158
<#frame_system::Pallet<T>>::deposit_event(event)

substrate/frame/support/procedural/src/pallet/parse/config.rs

Lines changed: 1 addition & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,6 @@ pub struct ConfigDef {
5959
pub consts_metadata: Vec<ConstMetadataDef>,
6060
/// Associated types metadata.
6161
pub associated_types_metadata: Vec<AssociatedTypeMetadataDef>,
62-
/// Whether the trait has the associated type `Event`, note that those bounds are
63-
/// checked:
64-
/// * `IsType<Self as frame_system::Config>::RuntimeEvent`
65-
/// * `From<Event>` or `From<Event<T>>` or `From<Event<T, I>>`
66-
pub has_event_type: bool,
67-
/// Whether the supertrait `frame_system::Config` defines associated type `RuntimeEvent`.
68-
pub has_event_bound: bool,
6962
/// The where clause on trait definition but modified so `Self` is `T`.
7063
pub where_clause: Option<syn::WhereClause>,
7164
/// Whether a default sub-trait should be generated.
@@ -371,38 +364,6 @@ fn contains_type_info_bound(ty: &TraitItemType) -> bool {
371364
})
372365
}
373366

374-
/// Check that supertrait `Config` contains `RuntimeEvent` associated type bound with
375-
/// `From<Event<Self>>`.
376-
///
377-
/// NOTE: Does not check if the supertrait path is valid system config path.
378-
///
379-
/// ```rs
380-
/// pub trait Config: frame_system::Config {
381-
/// ```
382-
fn contains_runtime_event_associated_type_bound(supertrait: &syn::Path) -> bool {
383-
if let Some(args) = supertrait.segments.iter().find(|s| s.ident == "Config") {
384-
if let syn::PathArguments::AngleBracketed(args) = &args.arguments {
385-
for arg in &args.args {
386-
if let syn::GenericArgument::Constraint(c) = arg {
387-
if c.ident != "RuntimeEvent" {
388-
continue;
389-
}
390-
391-
// Check `From<Event<Self>>` bound
392-
let from_event_bound = c
393-
.bounds
394-
.iter()
395-
.find_map(|s| syn::parse2::<FromEventParse>(s.to_token_stream()).ok());
396-
397-
return from_event_bound.is_some();
398-
}
399-
}
400-
}
401-
}
402-
403-
false
404-
}
405-
406367
impl ConfigDef {
407368
pub fn try_from(
408369
frame_system: &syn::Path,
@@ -444,16 +405,6 @@ impl ConfigDef {
444405
false
445406
};
446407

447-
let has_event_bound = if is_frame_system {
448-
false
449-
} else {
450-
item.supertraits.iter().any(|supertrait| {
451-
syn::parse2::<syn::Path>(supertrait.to_token_stream())
452-
.map_or(false, |b| contains_runtime_event_associated_type_bound(&b))
453-
})
454-
};
455-
456-
let mut has_event_type = false;
457408
let mut consts_metadata = vec![];
458409
let mut associated_types_metadata = vec![];
459410
let mut warnings = vec![];
@@ -464,7 +415,6 @@ impl ConfigDef {
464415
};
465416
for trait_item in &mut item.items {
466417
let is_event = check_event_type(frame_system, trait_item, has_instance)?;
467-
has_event_type = has_event_type || is_event;
468418

469419
let mut already_no_default = false;
470420
let mut already_constant = false;
@@ -480,7 +430,7 @@ impl ConfigDef {
480430
if !type_event.attrs.iter().any(|attr| attr == &allow_dep) {
481431
let warning = Warning::new_deprecated("RuntimeEvent")
482432
.old("have `RuntimeEvent` associated type in the pallet config")
483-
.new("remove it or explicitly define it as an associated type bound in the system supertrait: \n
433+
.new("remove it as it is redundant since associated bound gets appended automatically: \n
484434
pub trait Config: frame_system::Config<RuntimeEvent: From<Event<Self>>> { }")
485435
.help_link("https://github.com/paritytech/polkadot-sdk/pull/7229")
486436
.span(type_event.ident.span())
@@ -648,8 +598,6 @@ impl ConfigDef {
648598
has_instance,
649599
consts_metadata,
650600
associated_types_metadata,
651-
has_event_type,
652-
has_event_bound,
653601
where_clause,
654602
default_sub_trait,
655603
warnings,
@@ -774,52 +722,4 @@ mod tests {
774722
let path = syn::parse2::<syn::Path>(quote::quote!(something::Config)).unwrap();
775723
assert!(!has_expected_system_config(path, &frame_system));
776724
}
777-
778-
#[test]
779-
fn contains_runtime_event_associated_type_bound_no_bound() {
780-
let supertrait = syn::parse2::<syn::Path>(quote::quote!(frame_system::Config)).unwrap();
781-
assert!(!contains_runtime_event_associated_type_bound(&supertrait));
782-
}
783-
784-
#[test]
785-
fn contains_runtime_event_associated_type_bound_works() {
786-
let supertrait = syn::parse2::<syn::Path>(quote::quote!(Config));
787-
assert!(contains_runtime_event_associated_type_bound(&supertrait.unwrap()));
788-
}
789-
#[test]
790-
fn contains_runtime_event_associated_type_bound_works_interface() {
791-
let supertrait = syn::parse2::<syn::Path>(quote::quote!(
792-
Config<RuntimeEvent: From<Event<Self, I>>>
793-
));
794-
assert!(contains_runtime_event_associated_type_bound(&supertrait.unwrap()));
795-
}
796-
797-
#[test]
798-
fn contains_runtime_event_associated_type_bound_works_full_path() {
799-
let supertrait = syn::parse2::<syn::Path>(quote::quote!(frame_system::Config));
800-
assert!(contains_runtime_event_associated_type_bound(&supertrait.unwrap()));
801-
}
802-
803-
#[test]
804-
fn contains_runtime_event_associated_type_bound_invalid_supertrait() {
805-
let supertrait =
806-
syn::parse2::<syn::Path>(quote::quote!(SystemConfig<RuntimeEvent: From<Event<Self>>>))
807-
.unwrap();
808-
assert!(!contains_runtime_event_associated_type_bound(&supertrait));
809-
}
810-
811-
#[test]
812-
fn contains_runtime_event_associated_type_bound_invalid_assoc_type_name() {
813-
let supertrait =
814-
syn::parse2::<syn::Path>(quote::quote!(Config<NonRuntimeEvent: From<Event<Self>>>))
815-
.unwrap();
816-
assert!(!contains_runtime_event_associated_type_bound(&supertrait));
817-
}
818-
#[test]
819-
fn contains_runtime_event_associated_type_bound_invalid_trait_bound() {
820-
let supertrait =
821-
syn::parse2::<syn::Path>(quote::quote!(Config<RuntimeEvent: TryFrom<Event<Self>>>))
822-
.unwrap();
823-
assert!(!contains_runtime_event_associated_type_bound(&supertrait));
824-
}
825725
}

substrate/frame/support/procedural/src/pallet/parse/mod.rs

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub struct Def {
7272
pub frame_support: syn::Path,
7373
pub dev_mode: bool,
7474
pub view_functions: Option<view_functions::ViewFunctionsImplDef>,
75+
pub is_frame_system: bool,
7576
}
7677

7778
impl Def {
@@ -106,20 +107,23 @@ impl Def {
106107
let mut type_values = vec![];
107108
let mut composites: Vec<CompositeDef> = vec![];
108109
let mut view_functions = None;
110+
let mut is_frame_system = false;
109111

110112
for (index, item) in items.iter_mut().enumerate() {
111113
let pallet_attr: Option<PalletAttr> = helper::take_first_item_pallet_attr(item)?;
112114

113115
match pallet_attr {
114-
Some(PalletAttr::Config{ with_default, is_frame_system, without_automatic_metadata, ..}) if config.is_none() =>
116+
Some(PalletAttr::Config{ with_default, is_frame_system: is_frame_system_val, without_automatic_metadata, ..}) if config.is_none() => {
117+
is_frame_system = is_frame_system_val;
115118
config = Some(config::ConfigDef::try_from(
116119
&frame_system,
117120
index,
118121
item,
119122
with_default,
120123
without_automatic_metadata,
121124
is_frame_system,
122-
)?),
125+
)?);
126+
},
123127
Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => {
124128
let p = pallet_struct::PalletStructDef::try_from(span, index, item)?;
125129
pallet_struct = Some(p);
@@ -258,10 +262,10 @@ impl Def {
258262
frame_support,
259263
dev_mode,
260264
view_functions,
265+
is_frame_system,
261266
};
262267

263268
def.check_instance_usage()?;
264-
def.check_event_usage()?;
265269

266270
Ok(def)
267271
}
@@ -359,32 +363,6 @@ impl Def {
359363
Ok(())
360364
}
361365

362-
/// Check that usage of trait `Event` is consistent with the definition, i.e. it is declared
363-
/// and trait defines type or type bound `RuntimeEvent`, or not declared and no trait associated
364-
/// type.
365-
fn check_event_usage(&self) -> syn::Result<()> {
366-
match (self.config.has_event_type, self.config.has_event_bound, self.event.is_some()) {
367-
(true, false, false) => {
368-
let msg = "Invalid usage of RuntimeEvent, `Config` contains associated type `RuntimeEvent`, \
369-
but enum `Event` is not declared (i.e. no use of `#[pallet::event]`). \
370-
Note that type `RuntimeEvent` in trait is reserved to work alongside pallet event.";
371-
Err(syn::Error::new(proc_macro2::Span::call_site(), msg))
372-
},
373-
(false, true, false) => {
374-
let msg = "Invalid usage of `RuntimeEvent`, `frame_system::Config` contains associated type bound `RuntimeEvent`, \
375-
but enum `Event` is not declared (i.e. no use of `#[pallet::event]`). \
376-
Note that type associated type bound `RuntimeEvent` in trait is reserved to work alongside pallet event.";
377-
Err(syn::Error::new(proc_macro2::Span::call_site(), msg))
378-
},
379-
(true, true, _) => {
380-
let msg = "Invalid usage of RuntimeEvent, `Config` contains associated type `RuntimeEvent` and associated type bound `RuntimeEvent`. \
381-
Only one of them should be used.";
382-
Err(syn::Error::new(proc_macro2::Span::call_site(), msg))
383-
},
384-
_ => Ok(()),
385-
}
386-
}
387-
388366
/// Check that usage of trait `Config` is consistent with the definition, i.e. it is used with
389367
/// instance iff it is defined with instance.
390368
fn check_instance_usage(&self) -> syn::Result<()> {

0 commit comments

Comments
 (0)