From 83ebbbe2a8009db4b9b51868e2256a5f92799c59 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 14 Feb 2023 19:14:11 -0600 Subject: [PATCH 001/116] first draft, probably won't work --- frame/examples/basic/src/tests.rs | 5 ++- frame/system/src/lib.rs | 74 ++++++++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index d9a8a4e8e1cdc..a0d64a255f2bc 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -50,8 +50,11 @@ frame_support::construct_runtime!( } ); +use frame_system::pallet::preludes::testing::Impl; +type SystemRuntime = Impl; impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; + type BaseCallFilter = ::BaseCallFilter; + // type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); type DbWeight = (); diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 88291c326edba..7b0612e84d9ca 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -200,10 +200,77 @@ pub mod pallet { use crate::{self as frame_system, pallet_prelude::*, *}; use frame_support::pallet_prelude::*; + pub mod preludes { + use super::*; + pub mod testing { + type AccountId = u32; + use sp_runtime::traits::IdentityLookup; + + use super::*; + + // things that cannot have default are made into generics. + #[derive(frame_support::CloneNoBound, frame_support::EqNoBound, frame_support::PartialEqNoBound)] + pub struct TestImpl( + sp_std::marker::PhantomData<(RuntimeCall, RuntimeOrigin, RuntimeEvent, PalletInfo)>, + ); + impl Config + for TestImpl + where + RuntimeCall: Parameter + + Dispatchable + + Debug + + 'static + + From> + + Sync + + Send, + RuntimeOrigin: Into, RuntimeOrigin>> + + From> + + OriginTrait + + Clone + + 'static, + RuntimeEvent: Parameter + Member + From> + Debug + IsType, + PalletInfo: frame_support::traits::PalletInfo + 'static, + { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + + type Version = (); + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Index = u64; + type BlockNumber = u64; + type Hash = sp_core::hash::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = as sp_runtime::traits::Block>::Header; + type BlockHashCount = frame_support::traits::ConstU64<10>; + type PalletInfo = PalletInfo; + type AccountData = u32; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; + } + } + } + /// System configuration trait. Implemented by runtime. #[pallet::config] #[pallet::disable_frame_system_supertrait_check] pub trait Config: 'static + Eq + Clone { + /// The aggregated event type of the runtime. + type RuntimeEvent: Parameter + + Member + + From> + + Debug + + IsType<::RuntimeEvent>; + /// The basic call filter to use in Origin. All origins are built with this filter as base, /// except Root. type BaseCallFilter: Contains; @@ -294,13 +361,6 @@ pub mod pallet { /// The block header. type Header: Parameter + traits::Header; - /// The aggregated event type of the runtime. - type RuntimeEvent: Parameter - + Member - + From> - + Debug - + IsType<::RuntimeEvent>; - /// Maximum number of block number to block hash mappings to keep (oldest pruned first). #[pallet::constant] type BlockHashCount: Get; From 8597691c54f2dc88e189a450c0ffafc8d2705d8f Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 14 Feb 2023 19:14:39 -0600 Subject: [PATCH 002/116] first draft, probably won't work --- frame/system/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 7b0612e84d9ca..375d04b85489f 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -210,11 +210,11 @@ pub mod pallet { // things that cannot have default are made into generics. #[derive(frame_support::CloneNoBound, frame_support::EqNoBound, frame_support::PartialEqNoBound)] - pub struct TestImpl( + pub struct Impl( sp_std::marker::PhantomData<(RuntimeCall, RuntimeOrigin, RuntimeEvent, PalletInfo)>, ); impl Config - for TestImpl + for Impl where RuntimeCall: Parameter + Dispatchable From 8090642d0dba4ae4802eb226981c79727c029fd6 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 15 Feb 2023 08:18:25 -0600 Subject: [PATCH 003/116] good progress.. --- frame/examples/basic/src/tests.rs | 75 ++++++++++++++++++++----------- frame/system/src/lib.rs | 2 +- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index a0d64a255f2bc..9e615902c503e 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -17,6 +17,8 @@ //! Tests for pallet-example-basic. +use core::hash::Hash; + use crate::*; use frame_support::{ assert_ok, @@ -50,43 +52,66 @@ frame_support::construct_runtime!( } ); -use frame_system::pallet::preludes::testing::Impl; -type SystemRuntime = Impl; +type SystemRuntime = frame_system::pallet::preludes::testing::Impl< + RuntimeCall, + RuntimeOrigin, + RuntimeEvent, + PalletInfo, +>; + +impl From> for RuntimeCall { + fn from(_: frame_system::Call) -> Self { + unreachable!() + } +} + +impl From> for RuntimeEvent { + fn from(_: frame_system::Event) -> Self { + unreachable!() + } +} + impl frame_system::Config for Test { - type BaseCallFilter = ::BaseCallFilter; - // type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); + // these cannot be overwritten. type RuntimeOrigin = RuntimeOrigin; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + + // This one we want to overwrite. + type AccountData = pallet_balances::AccountData; + + // this causes some errors. + type Hash = H256; + // This causes the compiler to go into infinite loop. + type AccountId = u64; + + type BaseCallFilter = ::BaseCallFilter; + type BlockWeights = ::BlockWeights; + type BlockLength = ::BlockLength; + type DbWeight = ::DbWeight; + type Index = ::Index; + type BlockNumber = ::BlockNumber; + type Hashing = ::Hashing; + type Lookup = ::Lookup; + type Header = ::Header; + type BlockHashCount = ::BlockHashCount; + type Version = ::Version; + type OnNewAccount = ::OnNewAccount; + type OnKilledAccount = ::OnKilledAccount; + type SystemWeightInfo = ::SystemWeightInfo; + type SS58Prefix = ::SS58Prefix; + type OnSetCode = ::OnSetCode; + type MaxConsumers = ::MaxConsumers; } impl pallet_balances::Config for Test { + type RuntimeEvent = RuntimeEvent; type MaxLocks = (); type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -97,8 +122,8 @@ impl pallet_balances::Config for Test { } impl Config for Test { - type MagicNumber = ConstU64<1_000_000_000>; type RuntimeEvent = RuntimeEvent; + type MagicNumber = ConstU64<1_000_000_000>; type WeightInfo = (); } diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 375d04b85489f..f4905c41d6dc3 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -203,7 +203,7 @@ pub mod pallet { pub mod preludes { use super::*; pub mod testing { - type AccountId = u32; + type AccountId = u64; use sp_runtime::traits::IdentityLookup; use super::*; From 62941026bc250a0b8f8fa8667d738ffaea4cd042 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 21 Feb 2023 12:55:58 -0600 Subject: [PATCH 004/116] good milestone, still a lot to do. --- frame/balances/src/lib.rs | 2 + frame/examples/basic/src/lib.rs | 3 + frame/examples/basic/src/tests.rs | 83 +++++++---- .../procedural/src/pallet/expand/config.rs | 13 +- .../procedural/src/pallet/parse/config.rs | 129 ++++++++++++++---- .../procedural/src/pallet/parse/helper.rs | 4 +- frame/system/src/lib.rs | 98 +++++-------- 7 files changed, 217 insertions(+), 115 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index d4be806982dfe..6594c3967d070 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -233,6 +233,7 @@ pub mod pallet { + FixedPointOperand; /// Handler for the unbalanced reduction when removing a dust account. + #[pallet::no_default] type DustRemoval: OnUnbalanced>; /// The minimum amount required to keep an account open. MUST BE GREATER THAN ZERO! @@ -247,6 +248,7 @@ pub mod pallet { type ExistentialDeposit: Get; /// The means of storing the balances of an account. + #[pallet::no_default] type AccountStore: StoredMap>; /// The ID type for reserves. diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index 6665c3b78b024..2e8a0403e14e8 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -367,6 +367,8 @@ pub mod pallet { pub trait Config: pallet_balances::Config + frame_system::Config { // Setting a constant config parameter from the runtime #[pallet::constant] + #[pallet::no_default] + // It is very unfortunate that we cannot have this have a default either, because it relies on `` type MagicNumber: Get; /// The overarching event type. @@ -374,6 +376,7 @@ pub mod pallet { /// Type representing the weight of this pallet type WeightInfo: WeightInfo; + } // Simple declaration of the `Pallet` type. It is placeholder we use to implement traits and diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 9e615902c503e..5434fc9d7d379 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -23,9 +23,10 @@ use crate::*; use frame_support::{ assert_ok, dispatch::{DispatchInfo, GetDispatchInfo}, - traits::{ConstU64, OnInitialize}, + traits::{ConstU64, Hash as _, OnInitialize}, }; use sp_core::H256; +use sp_io::DefaultChildStorage; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use sp_runtime::{ @@ -52,6 +53,22 @@ frame_support::construct_runtime!( } ); +// Overall goal: implement config of a pallet for some struct `Impl`, while implementing the +// `Config` for `Runtime`, use `Impl` to get the defaults. We first do it manually, later on we will +// use a derive macro.w +// +// 3 approaches: +// 1. implement the real config using generics for things that cannot be mocked. +// - lead to unexpected compiler issues. +// 2. implement the real config using fake types for things that cannot be a +// - not fully explored. +// 3. generate a sub `DefaultConfig` that only has the things that can have a default, implement +// that. +// +// Option 3 seems to be the best at the end of the day because it will also avoid the need to +// implement `system::Config`. + +// parameterize `testing::Impl` with the items that cannot have a default. type SystemRuntime = frame_system::pallet::preludes::testing::Impl< RuntimeCall, RuntimeOrigin, @@ -59,52 +76,64 @@ type SystemRuntime = frame_system::pallet::preludes::testing::Impl< PalletInfo, >; +// a bit of extra boilerplate needed to make the compiler happy. impl From> for RuntimeCall { fn from(_: frame_system::Call) -> Self { unreachable!() } } - impl From> for RuntimeEvent { fn from(_: frame_system::Event) -> Self { unreachable!() } } +type SystemRuntime2 = frame_system::preludes::testing::Impl2; + +// Once this impl block can almost gully be delegated to `SystemRuntime`, we can move it to a +// proc-macro. That's the easy part. +type __AccountId = ::AccountId; +type __Hash = ::Hash; + + + + + + + + + + + + +#[frame_system::derive_impl(test)] impl frame_system::Config for Test { // these cannot be overwritten. type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; + type BaseCallFilter = frame_support::traits::Everything; + type OnSetCode = (); + type Header = ::Header; - // This one we want to overwrite. - type AccountData = pallet_balances::AccountData; - - // this causes some errors. - type Hash = H256; - // This causes the compiler to go into infinite loop. - type AccountId = u64; - - type BaseCallFilter = ::BaseCallFilter; - type BlockWeights = ::BlockWeights; - type BlockLength = ::BlockLength; - type DbWeight = ::DbWeight; - type Index = ::Index; - type BlockNumber = ::BlockNumber; - type Hashing = ::Hashing; - type Lookup = ::Lookup; - type Header = ::Header; - type BlockHashCount = ::BlockHashCount; - type Version = ::Version; - type OnNewAccount = ::OnNewAccount; - type OnKilledAccount = ::OnKilledAccount; - type SystemWeightInfo = ::SystemWeightInfo; - type SS58Prefix = ::SS58Prefix; - type OnSetCode = ::OnSetCode; - type MaxConsumers = ::MaxConsumers; + // type AccountId = u32; + // type AccountId = ::AccountId; + type X = ::X; + type Y = ::Y; + type Z = ::Z; } + + + + + + + + + + impl pallet_balances::Config for Test { type RuntimeEvent = RuntimeEvent; type MaxLocks = (); diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index c70f6eb80422a..07ad5cbb4cb54 100644 --- a/frame/support/procedural/src/pallet/expand/config.rs +++ b/frame/support/procedural/src/pallet/expand/config.rs @@ -41,5 +41,16 @@ pub fn expand_config(def: &mut Def) -> proc_macro2::TokenStream { )); } - Default::default() + if let Some(trait_items) = &config.default_sub_trait { + use quote::ToTokens; + let items = trait_items.into_iter().map(|i| i.into_token_stream()).collect::(); + quote::quote!( + pub trait DefaultConfig { + #items + } + ) + } else { + Default::default() + } + } diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 4d22e50ef2bbf..b42b06d6aaa6f 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -31,6 +31,7 @@ mod keyword { syn::custom_keyword!(RuntimeEvent); syn::custom_keyword!(Event); syn::custom_keyword!(constant); + syn::custom_keyword!(no_default); syn::custom_keyword!(frame_system); syn::custom_keyword!(disable_frame_system_supertrait_check); } @@ -52,6 +53,11 @@ pub struct ConfigDef { pub where_clause: Option, /// The span of the pallet::config attribute. pub attr_span: proc_macro2::Span, + /// Whether a default sub-trait should be generated. + /// + /// No, if `None`. + /// Yes, if `Some(_)`, with the inner items that should be included. + pub default_sub_trait: Option>, } /// Input definition for a constant in pallet config. @@ -144,6 +150,61 @@ impl syn::parse::Parse for TypeAttrConst { } } +/// Parse for `#[pallet::no_default]`. +pub struct TypeAttrNoDefault(proc_macro2::Span); + +impl Spanned for TypeAttrNoDefault { + fn span(&self) -> proc_macro2::Span { + self.0 + } +} + +impl syn::parse::Parse for TypeAttrNoDefault { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + input.parse::()?; + let content; + syn::bracketed!(content in input); + content.parse::()?; + content.parse::()?; + + Ok(TypeAttrNoDefault(content.parse::()?.span())) + } +} + +pub enum TypeAttrNoDefaultOrConst { + NoDefault(TypeAttrNoDefault), + Const(TypeAttrConst), +} + +impl Spanned for TypeAttrNoDefaultOrConst { + fn span(&self) -> proc_macro2::Span { + match self { + Self::Const(i) => i.0, + Self::NoDefault(i) => i.0, + } + } +} + +impl syn::parse::Parse for TypeAttrNoDefaultOrConst { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + input.parse::()?; + let content; + syn::bracketed!(content in input); + content.parse::()?; + content.parse::()?; + + Ok(if content.peek(keyword::no_default) { + TypeAttrNoDefaultOrConst::NoDefault(TypeAttrNoDefault( + content.parse::()?.span(), + )) + } else { + TypeAttrNoDefaultOrConst::Const(TypeAttrConst( + content.parse::()?.span(), + )) + }) + } +} + /// Parse for `$ident::Config` pub struct ConfigBoundParse(syn::Ident); @@ -332,38 +393,52 @@ impl ConfigDef { let mut has_event_type = false; let mut consts_metadata = vec![]; + let mut default_subtrait_items = vec![]; for trait_item in &mut item.items { // Parse for event - has_event_type = - has_event_type || check_event_type(frame_system, trait_item, has_instance)?; - - // Parse for constant - let type_attrs_const: Vec = helper::take_item_pallet_attrs(trait_item)?; - - if type_attrs_const.len() > 1 { - let msg = "Invalid attribute in pallet::config, only one attribute is expected"; - return Err(syn::Error::new(type_attrs_const[1].span(), msg)) - } - - if type_attrs_const.len() == 1 { - match trait_item { - syn::TraitItem::Type(ref type_) => { - let constant = ConstMetadataDef::try_from(type_)?; - consts_metadata.push(constant); + let is_event = check_event_type(frame_system, trait_item, has_instance)?; + let mut no_default = false; + has_event_type = has_event_type || is_event; + + // TODO: lots of extra checking that needs to be done.. this is just POC + let mut process_attr = || { + let no_default_or_const: Option = + helper::take_first_item_pallet_attr(trait_item)?; + match no_default_or_const { + Some(TypeAttrNoDefaultOrConst::Const(_)) => match trait_item { + syn::TraitItem::Type(ref type_) => { + let constant = ConstMetadataDef::try_from(type_)?; + consts_metadata.push(constant); + }, + _ => { + let msg = + "Invalid pallet::constant in pallet::config, expected type trait item"; + return Err(syn::Error::new(trait_item.span(), msg)) + }, }, - _ => { - let msg = - "Invalid pallet::constant in pallet::config, expected type trait \ - item"; - return Err(syn::Error::new(trait_item.span(), msg)) + Some(TypeAttrNoDefaultOrConst::NoDefault(_)) => { + no_default = true; }, + None => {}, } + Ok(()) + }; + + // process at most twice. + process_attr()?; + process_attr()?; + + // TODO: if we call this again, we should expect `Err(_)`. + + if !no_default && !is_event { + default_subtrait_items.push(trait_item.clone()); } } + let default_sub_trait = Some(default_subtrait_items); + let attr: Option = helper::take_first_item_pallet_attr(&mut item.attrs)?; - let disable_system_supertrait_check = attr.is_some(); let has_frame_system_supertrait = item.supertraits.iter().any(|s| { @@ -395,6 +470,14 @@ impl ConfigDef { return Err(syn::Error::new(item.span(), msg)) } - Ok(Self { index, has_instance, consts_metadata, has_event_type, where_clause, attr_span }) + Ok(Self { + index, + has_instance, + consts_metadata, + has_event_type, + where_clause, + attr_span, + default_sub_trait, + }) } } diff --git a/frame/support/procedural/src/pallet/parse/helper.rs b/frame/support/procedural/src/pallet/parse/helper.rs index 4814dce5a3dfa..0e68e1abc4cbf 100644 --- a/frame/support/procedural/src/pallet/parse/helper.rs +++ b/frame/support/procedural/src/pallet/parse/helper.rs @@ -47,7 +47,7 @@ pub trait MutItemAttrs { } /// Take the first pallet attribute (e.g. attribute like `#[pallet..]`) and decode it to `Attr` -pub fn take_first_item_pallet_attr(item: &mut impl MutItemAttrs) -> syn::Result> +pub(crate) fn take_first_item_pallet_attr(item: &mut impl MutItemAttrs) -> syn::Result> where Attr: syn::parse::Parse, { @@ -64,7 +64,7 @@ where } /// Take all the pallet attributes (e.g. attribute like `#[pallet..]`) and decode them to `Attr` -pub fn take_item_pallet_attrs(item: &mut impl MutItemAttrs) -> syn::Result> +pub(crate) fn take_item_pallet_attrs(item: &mut impl MutItemAttrs) -> syn::Result> where Attr: syn::parse::Parse, { diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index f4905c41d6dc3..1881e1553d5a1 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -153,12 +153,13 @@ pub type ConsumedWeight = PerDispatchClass; pub use pallet::*; /// Do something when we should be setting the code. -pub trait SetCode { +pub trait SetCode { /// Set the code to the given blob. fn set_code(code: Vec) -> DispatchResult; } -impl SetCode for () { +pub struct DefaultSetCode(sp_std::marker::PhantomData); +impl SetCode for DefaultSetCode { fn set_code(code: Vec) -> DispatchResult { >::update_code_in_storage(&code)?; Ok(()) @@ -200,65 +201,35 @@ pub mod pallet { use crate::{self as frame_system, pallet_prelude::*, *}; use frame_support::pallet_prelude::*; - pub mod preludes { - use super::*; - pub mod testing { - type AccountId = u64; - use sp_runtime::traits::IdentityLookup; - - use super::*; - - // things that cannot have default are made into generics. - #[derive(frame_support::CloneNoBound, frame_support::EqNoBound, frame_support::PartialEqNoBound)] - pub struct Impl( - sp_std::marker::PhantomData<(RuntimeCall, RuntimeOrigin, RuntimeEvent, PalletInfo)>, - ); - impl Config - for Impl - where - RuntimeCall: Parameter - + Dispatchable - + Debug - + 'static - + From> - + Sync - + Send, - RuntimeOrigin: Into, RuntimeOrigin>> - + From> - + OriginTrait - + Clone - + 'static, - RuntimeEvent: Parameter + Member + From> + Debug + IsType, - PalletInfo: frame_support::traits::PalletInfo + 'static, - { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - - type Version = (); - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type Index = u64; - type BlockNumber = u64; - type Hash = sp_core::hash::H256; - type Hashing = sp_runtime::traits::BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = as sp_runtime::traits::Block>::Header; - type BlockHashCount = frame_support::traits::ConstU64<10>; - type PalletInfo = PalletInfo; - type AccountData = u32; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; - } - } - } + // pub mod preludes { + // use super::*; + // pub mod testing { + // type AccountId = u64; + // use sp_runtime::traits::IdentityLookup; + // use super::*; + + // pub struct Impl {} + // impl DefaultConfig for Impl { + // type Version = (); + // type BlockWeights = (); + // type BlockLength = (); + // type DbWeight = (); + // type Index = u64; + // type BlockNumber = u64; + // type Hash = sp_core::hash::H256; + // type Hashing = sp_runtime::traits::BlakeTwo256; + // type AccountId = AccountId; + // type Lookup = IdentityLookup; + // type BlockHashCount = frame_support::traits::ConstU64<10>; + // type AccountData = u32; + // type OnNewAccount = (); + // type OnKilledAccount = (); + // type SystemWeightInfo = (); + // type SS58Prefix = (); + // type MaxConsumers = ConstU32<16>; + // } + // } + // } /// System configuration trait. Implemented by runtime. #[pallet::config] @@ -273,6 +244,7 @@ pub mod pallet { /// The basic call filter to use in Origin. All origins are built with this filter as base, /// except Root. + #[pallet::no_default] type BaseCallFilter: Contains; /// Block & extrinsics weights: base values and limits. @@ -284,12 +256,14 @@ pub mod pallet { type BlockLength: Get; /// The `RuntimeOrigin` type used by dispatchable calls. + #[pallet::no_default] type RuntimeOrigin: Into, Self::RuntimeOrigin>> + From> + Clone + OriginTrait; /// The aggregated `RuntimeCall` type. + #[pallet::no_default] type RuntimeCall: Parameter + Dispatchable + Debug @@ -410,7 +384,7 @@ pub mod pallet { /// [`Pallet::update_code_in_storage`]). /// It's unlikely that this needs to be customized, unless you are writing a parachain using /// `Cumulus`, where the actual code change is deferred. - type OnSetCode: SetCode; + type OnSetCode: SetCode; /// The maximum number of consumers allowed on a single account. type MaxConsumers: ConsumerLimits; From a0a6423f7d07e36f12d0a7f2b30a90c2eb3f3f97 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 23 Feb 2023 17:50:51 -0600 Subject: [PATCH 005/116] EVERYTHING WORKS --- frame/examples/basic/src/tests.rs | 119 +++++-------- frame/nomination-pools/src/lib.rs | 3 + .../procedural/src/construct_runtime/mod.rs | 2 +- frame/support/procedural/src/derive_impl.rs | 158 ++++++++++++++++++ frame/support/procedural/src/lib.rs | 15 ++ .../procedural/src/pallet/expand/config.rs | 36 +++- frame/support/src/lib.rs | 6 + frame/system/src/lib.rs | 63 +++---- 8 files changed, 287 insertions(+), 115 deletions(-) create mode 100644 frame/support/procedural/src/derive_impl.rs diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 5434fc9d7d379..ff9b8fd7f7ff7 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -17,16 +17,13 @@ //! Tests for pallet-example-basic. -use core::hash::Hash; - use crate::*; use frame_support::{ assert_ok, dispatch::{DispatchInfo, GetDispatchInfo}, - traits::{ConstU64, Hash as _, OnInitialize}, + traits::{ConstU64, OnInitialize}, }; use sp_core::H256; -use sp_io::DefaultChildStorage; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use sp_runtime::{ @@ -53,94 +50,54 @@ frame_support::construct_runtime!( } ); -// Overall goal: implement config of a pallet for some struct `Impl`, while implementing the -// `Config` for `Runtime`, use `Impl` to get the defaults. We first do it manually, later on we will -// use a derive macro.w -// -// 3 approaches: -// 1. implement the real config using generics for things that cannot be mocked. -// - lead to unexpected compiler issues. -// 2. implement the real config using fake types for things that cannot be a -// - not fully explored. -// 3. generate a sub `DefaultConfig` that only has the things that can have a default, implement -// that. -// -// Option 3 seems to be the best at the end of the day because it will also avoid the need to -// implement `system::Config`. - -// parameterize `testing::Impl` with the items that cannot have a default. -type SystemRuntime = frame_system::pallet::preludes::testing::Impl< - RuntimeCall, - RuntimeOrigin, - RuntimeEvent, - PalletInfo, ->; - -// a bit of extra boilerplate needed to make the compiler happy. -impl From> for RuntimeCall { - fn from(_: frame_system::Call) -> Self { - unreachable!() - } -} -impl From> for RuntimeEvent { - fn from(_: frame_system::Event) -> Self { - unreachable!() - } -} - -type SystemRuntime2 = frame_system::preludes::testing::Impl2; - -// Once this impl block can almost gully be delegated to `SystemRuntime`, we can move it to a -// proc-macro. That's the easy part. -type __AccountId = ::AccountId; -type __Hash = ::Hash; - - - - - - - - - - - - -#[frame_system::derive_impl(test)] +#[frame_support::derive_impl(frame_system::preludes::testing::Impl)] impl frame_system::Config for Test { - // these cannot be overwritten. - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; + // These are all defined by system as mandatory. + type BaseCallFilter = frame_support::traits::Everything; type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type RuntimeOrigin = RuntimeOrigin; + type OnSetCode = frame_system::DefaultSetCode; type PalletInfo = PalletInfo; - type BaseCallFilter = frame_support::traits::Everything; - type OnSetCode = (); - type Header = ::Header; - - // type AccountId = u32; - // type AccountId = ::AccountId; - type X = ::X; - type Y = ::Y; - type Z = ::Z; + type Header = Header; + // We decide to override this one. + type AccountData = pallet_balances::AccountData; } - - - - - - - - - +// impl frame_system::Config for Test { +// type BaseCallFilter = frame_support::traits::Everything; +// type BlockWeights = (); +// type BlockLength = (); +// type DbWeight = (); +// type RuntimeOrigin = RuntimeOrigin; +// type Index = u64; +// type BlockNumber = u64; +// type Hash = H256; +// type RuntimeCall = RuntimeCall; +// type Hashing = BlakeTwo256; +// type AccountId = u64; +// type Lookup = IdentityLookup; +// type Header = Header; +// type RuntimeEvent = RuntimeEvent; +// type BlockHashCount = ConstU64<250>; +// type Version = (); +// type PalletInfo = PalletInfo; +// type AccountData = pallet_balances::AccountData; +// type OnNewAccount = (); +// type OnKilledAccount = (); +// type SystemWeightInfo = (); +// type SS58Prefix = (); +// type OnSetCode = frame_system::DefaultSetCode; +// type MaxConsumers = frame_support::traits::ConstU32<16>; +// } impl pallet_balances::Config for Test { - type RuntimeEvent = RuntimeEvent; type MaxLocks = (); type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -151,8 +108,8 @@ impl pallet_balances::Config for Test { } impl Config for Test { - type RuntimeEvent = RuntimeEvent; type MagicNumber = ConstU64<1_000_000_000>; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index cfde05ffeeabe..8d6dea9b5b7ad 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1494,6 +1494,7 @@ pub mod pallet { use frame_support::traits::StorageVersion; use frame_system::{ensure_signed, pallet_prelude::*}; use sp_runtime::Perbill; + use sp_core::parameter_types; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); @@ -1511,6 +1512,7 @@ pub mod pallet { type WeightInfo: weights::WeightInfo; /// The nominating balance. + #[pallet::no_default] type Currency: Currency; /// The type that is used for reward counter. @@ -1553,6 +1555,7 @@ pub mod pallet { type U256ToBalance: Convert>; /// The interface for nominating. + #[pallet::no_default] type Staking: StakingInterface, AccountId = Self::AccountId>; /// The amount of eras a `SubPools::with_era` pool can exist before it gets merged into the diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 37f23efed36c1..ba4d7bf1f5131 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -24,7 +24,7 @@ //! `::{Call, ...}` or implicitly. //! //! In case a pallet defines its parts implicitly, then the pallet must provide the -//! `tt_default_parts` macro. `construct_rutime` will generate some code which utilizes `tt_call` +//! `tt_default_parts` macro. `construct_runtime` will generate some code which utilizes `tt_call` //! to call the `tt_default_parts` macro of the pallet. `tt_default_parts` will then return the //! default pallet parts as input tokens to the `match_and_replace` macro, which ultimately //! generates a call to `construct_runtime` again, this time with all the pallet parts explicitly diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs new file mode 100644 index 0000000000000..22836fa5ed6ff --- /dev/null +++ b/frame/support/procedural/src/derive_impl.rs @@ -0,0 +1,158 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Implementation of the `storage_alias` attribute macro. + +use frame_support_procedural_tools::generate_crate_access_2018; +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{punctuated::Punctuated, ItemImpl, Result, Token}; + +mod keywords { + syn::custom_keyword!(derive_impl); + syn::custom_keyword!(partial_impl_block); + syn::custom_keyword!(implementing_type); + syn::custom_keyword!(type_items); + syn::custom_keyword!(fn_items); + syn::custom_keyword!(const_items); +} + +pub struct DeriveImplDef { + /// The partial impl block that the user provides. This should be interpreted as "override". + partial_impl_block: syn::ItemImpl, + /// The full path to the type that can be used to receive defaults form. + implementing_type: syn::TypePath, + /// All of the associated type items that we must eventually implement. + type_items: Punctuated, + /// All of the function items that we must eventually implement. + fn_items: Punctuated, + /// All of the constant items that we must eventually implement. + const_items: Punctuated, +} + +impl syn::parse::Parse for DeriveImplDef { + fn parse(input: syn::parse::ParseStream) -> Result { + // NOTE: unfortunately, the order the keywords here must match what the pallet macro + // expands. We can probably used a shared set of keywords later. + let mut partial_impl_block; + let _ = input.parse::()?; + let _ = input.parse::()?; + let _replace_with_bracket: syn::token::Bracket = + syn::bracketed!(partial_impl_block in input); + let _replace_with_brace: syn::token::Brace = + syn::braced!(partial_impl_block in partial_impl_block); + let partial_impl_block = partial_impl_block.parse()?; + + let mut implementing_type; + let _ = input.parse::()?; + let _ = input.parse::()?; + let _replace_with_bracket: syn::token::Bracket = + syn::bracketed!(implementing_type in input); + let _replace_with_brace: syn::token::Brace = + syn::braced!(implementing_type in implementing_type); + let implementing_type = implementing_type.parse()?; + + let mut type_items; + let _ = input.parse::()?; + let _ = input.parse::()?; + let _replace_with_bracket: syn::token::Bracket = syn::bracketed!(type_items in input); + let _replace_with_brace: syn::token::Brace = syn::braced!(type_items in type_items); + let type_items = Punctuated::::parse_terminated(&type_items)?; + + let mut fn_items; + let _ = input.parse::()?; + let _ = input.parse::()?; + let _replace_with_bracket: syn::token::Bracket = syn::bracketed!(fn_items in input); + let _replace_with_brace: syn::token::Brace = syn::braced!(fn_items in fn_items); + let fn_items = Punctuated::::parse_terminated(&fn_items)?; + + let mut const_items; + let _ = input.parse::()?; + let _ = input.parse::()?; + let _replace_with_bracket: syn::token::Bracket = syn::bracketed!(const_items in input); + let _replace_with_brace: syn::token::Brace = syn::braced!(const_items in const_items); + let const_items = Punctuated::::parse_terminated(&const_items)?; + + Ok(Self { partial_impl_block, type_items, fn_items, const_items, implementing_type }) + } +} + +pub(crate) fn derive_impl_inner(input: TokenStream) -> Result { + println!("input: {}", input); + let DeriveImplDef { partial_impl_block, implementing_type, type_items, .. } = + syn::parse2(input)?; + + let type_item_name = |i: &syn::ImplItem| { + if let syn::ImplItem::Type(t) = i { + t.ident.clone() + } else { + panic!("only support type items for now") + } + }; + + // might be able to mutate `partial_impl_block` along the way, but easier like this for now. + let mut final_impl_block = partial_impl_block.clone(); + let source_crate_path = implementing_type.path.segments.first().unwrap().ident.clone(); + + // TODO: ensure type ident specified in `partial_impl_block` is beyond union(type_items, + // const_items, fn_items). + assert!( + partial_impl_block + .items + .iter() + .all(|i| { type_items.iter().find(|tt| tt == &&type_item_name(i)).is_some() }), + "some item in the partial_impl_block is unexpected" + ); + + // for each item that is in `type_items` but not present in `partial_impl_block`, fill it in. + type_items.iter().for_each(|ident| { + if partial_impl_block.items.iter().any(|i| &type_item_name(i) == ident) { + // this is already present in the partial impl block -- noop + } else { + // add it + let tokens = quote::quote!(type #ident = <#implementing_type as #source_crate_path::pallet::DefaultConfig>::#ident;); + let parsed: syn::ImplItem = syn::parse2(tokens).expect("it is a valid type item"); + debug_assert!(matches!(parsed, syn::ImplItem::Type(_))); + + final_impl_block.items.push(parsed) + } + }); + + Ok(quote::quote!(#final_impl_block)) +} + +pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> Result { + let implementing_type: syn::TypePath = syn::parse2(attrs.clone())?; + // ideas for sam: + // let other_path_tokens = magic_macro!(path_to_other_path_token); + // let foreign_trait_def_token: Syn::TraitItem = magic_macro!(frame_system::Config); + + let frame_support = generate_crate_access_2018("frame-support")?; + // TODO: may not be accurate. + let source_crate_path = implementing_type.path.segments.first().unwrap().ident.clone(); + + Ok(quote::quote!( + #frame_support::tt_call! { + macro = [{ #source_crate_path::tt_config_items }] + frame_support = [{ #frame_support }] + ~~> #frame_support::derive_impl_inner! { + partial_impl_block = [{ #input }] + implementing_type = [{ #attrs }] + } + } + )) +} diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 45f22202991e8..0c62f9f625594 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -35,6 +35,7 @@ mod storage; mod storage_alias; mod transactional; mod tt_macro; +mod derive_impl; use proc_macro::TokenStream; use quote::quote; @@ -776,6 +777,20 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { .into() } +#[proc_macro_attribute] +pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { + derive_impl::derive_impl(attrs.into(), input.into()) + .unwrap_or_else(|r| r.into_compile_error()) + .into() +} + +#[proc_macro] +pub fn derive_impl_inner(input: TokenStream) -> TokenStream { + derive_impl::derive_impl_inner(input.into()) + .unwrap_or_else(|r| r.into_compile_error()) + .into() +} + /// Used internally to decorate pallet attribute macro stubs when they are erroneously used /// outside of a pallet module fn pallet_macro_stub() -> TokenStream { diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index 07ad5cbb4cb54..6bcca96b4e06a 100644 --- a/frame/support/procedural/src/pallet/expand/config.rs +++ b/frame/support/procedural/src/pallet/expand/config.rs @@ -42,15 +42,43 @@ pub fn expand_config(def: &mut Def) -> proc_macro2::TokenStream { } if let Some(trait_items) = &config.default_sub_trait { - use quote::ToTokens; - let items = trait_items.into_iter().map(|i| i.into_token_stream()).collect::(); + let associated_type_names = config_item + .items + .iter() + .filter_map( + |i| if let syn::TraitItem::Type(t) = i { Some(t.ident.clone()) } else { None }, + ) + .collect::>(); + + // we rarely use const and fns in config traits anyways... maybe not supporting them is good enough. + let const_names = Vec::::default(); + let fn_names = Vec::::default(); + quote::quote!( pub trait DefaultConfig { - #items + #(#trait_items)* + } + + #[macro_export] + #[doc(hidden)] + // TODO: naming probably needs to be unique + macro_rules! tt_config_items { + { + $caller:tt + frame_support = [{$($frame_support:ident)::*}] + } => { + $( $frame_support )*::tt_return! { + $caller + type_items = [{ #(#associated_type_names),* }] + fn_items = [{ }] + const_items = [{ }] + } + } } + + pub use tt_config_items as tt_config_items; ) } else { Default::default() } - } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index b845828455793..8e1a707d4c60e 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -211,6 +211,12 @@ impl TypeId for PalletId { /// ``` pub use frame_support_procedural::storage_alias; +/// FOOO +pub use frame_support_procedural::derive_impl; +#[doc(hidden)] +pub use frame_support_procedural::derive_impl_inner; + + /// Create new implementations of the [`Get`](crate::traits::Get) trait. /// /// The so-called parameter type can be created in four different ways: diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 1881e1553d5a1..32520ab7553bd 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -201,38 +201,39 @@ pub mod pallet { use crate::{self as frame_system, pallet_prelude::*, *}; use frame_support::pallet_prelude::*; - // pub mod preludes { - // use super::*; - // pub mod testing { - // type AccountId = u64; - // use sp_runtime::traits::IdentityLookup; - // use super::*; - - // pub struct Impl {} - // impl DefaultConfig for Impl { - // type Version = (); - // type BlockWeights = (); - // type BlockLength = (); - // type DbWeight = (); - // type Index = u64; - // type BlockNumber = u64; - // type Hash = sp_core::hash::H256; - // type Hashing = sp_runtime::traits::BlakeTwo256; - // type AccountId = AccountId; - // type Lookup = IdentityLookup; - // type BlockHashCount = frame_support::traits::ConstU64<10>; - // type AccountData = u32; - // type OnNewAccount = (); - // type OnKilledAccount = (); - // type SystemWeightInfo = (); - // type SS58Prefix = (); - // type MaxConsumers = ConstU32<16>; - // } - // } - // } + pub mod preludes { + use super::*; + pub mod testing { + type AccountId = u64; + use sp_runtime::traits::IdentityLookup; + use super::*; + + pub struct Impl {} + impl DefaultConfig for Impl { + type Version = (); + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Index = u64; + type BlockNumber = u64; + type Hash = sp_core::hash::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type BlockHashCount = frame_support::traits::ConstU64<10>; + type AccountData = u32; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type MaxConsumers = ConstU32<16>; + } + } + } /// System configuration trait. Implemented by runtime. #[pallet::config] + // TODO: #[pallet::default_config] #[pallet::disable_frame_system_supertrait_check] pub trait Config: 'static + Eq + Clone { /// The aggregated event type of the runtime. @@ -245,6 +246,7 @@ pub mod pallet { /// The basic call filter to use in Origin. All origins are built with this filter as base, /// except Root. #[pallet::no_default] + // enum Everything is a reasonable default, but it is not possible. type BaseCallFilter: Contains; /// Block & extrinsics weights: base values and limits. @@ -333,6 +335,7 @@ pub mod pallet { type Lookup: StaticLookup; /// The block header. + #[pallet::no_default] type Header: Parameter + traits::Header; /// Maximum number of block number to block hash mappings to keep (oldest pruned first). @@ -353,6 +356,7 @@ pub mod pallet { /// runtime. /// /// For tests it is okay to use `()` as type, however it will provide "useless" data. + #[pallet::no_default] type PalletInfo: PalletInfo; /// Data to be associated with an account (other than nonce/transaction counter, which this @@ -384,6 +388,7 @@ pub mod pallet { /// [`Pallet::update_code_in_storage`]). /// It's unlikely that this needs to be customized, unless you are writing a parachain using /// `Cumulus`, where the actual code change is deferred. + #[pallet::no_default] type OnSetCode: SetCode; /// The maximum number of consumers allowed on a single account. From 749df494cf8270d31f773c24f4db09158ce586d2 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 7 Mar 2023 08:50:22 -0600 Subject: [PATCH 006/116] Update frame/support/procedural/src/derive_impl.rs Co-authored-by: Oliver Tale-Yazdi --- frame/support/procedural/src/derive_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 22836fa5ed6ff..ac5f60311624e 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Implementation of the `storage_alias` attribute macro. +//! Implementation of the `derive_impl` attribute macro. use frame_support_procedural_tools::generate_crate_access_2018; use proc_macro2::TokenStream; From 077713610c1d3989a8510b49bc9720eb04b97fc6 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 7 Mar 2023 08:50:29 -0600 Subject: [PATCH 007/116] Update frame/support/procedural/src/derive_impl.rs Co-authored-by: Oliver Tale-Yazdi --- frame/support/procedural/src/derive_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index ac5f60311624e..70c5901722a9f 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); From 7d5d50fb44e236dbb7d449ae4b00c0a670202a0a Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 7 Mar 2023 16:37:35 -0500 Subject: [PATCH 008/116] clean up + cargo fmt --- frame/examples/basic/src/lib.rs | 4 +- frame/support/procedural/src/derive_impl.rs | 91 ++++++++++--------- frame/support/procedural/src/lib.rs | 2 +- .../procedural/src/pallet/expand/config.rs | 3 +- .../procedural/src/pallet/parse/helper.rs | 4 +- frame/support/src/lib.rs | 1 - frame/system/src/lib.rs | 2 +- 7 files changed, 56 insertions(+), 51 deletions(-) diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index 2e8a0403e14e8..706a088fa97f6 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -368,7 +368,8 @@ pub mod pallet { // Setting a constant config parameter from the runtime #[pallet::constant] #[pallet::no_default] - // It is very unfortunate that we cannot have this have a default either, because it relies on `` + // It is very unfortunate that we cannot have this have a default either, because it relies + // on `` type MagicNumber: Get; /// The overarching event type. @@ -376,7 +377,6 @@ pub mod pallet { /// Type representing the weight of this pallet type WeightInfo: WeightInfo; - } // Simple declaration of the `Pallet` type. It is placeholder we use to implement traits and diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 70c5901722a9f..f9b864dc9dbe5 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -19,73 +19,77 @@ use frame_support_procedural_tools::generate_crate_access_2018; use proc_macro2::TokenStream; -use quote::ToTokens; -use syn::{punctuated::Punctuated, ItemImpl, Result, Token}; +use syn::{ + braced, bracketed, + parse::{Parse, ParseStream}, + parse2, + punctuated::Punctuated, + token::{Brace, Bracket}, + Ident, ImplItem, ItemImpl, Result, Token, TypePath, +}; mod keywords { - syn::custom_keyword!(derive_impl); - syn::custom_keyword!(partial_impl_block); - syn::custom_keyword!(implementing_type); - syn::custom_keyword!(type_items); - syn::custom_keyword!(fn_items); - syn::custom_keyword!(const_items); + use syn::custom_keyword; + + custom_keyword!(derive_impl); + custom_keyword!(partial_impl_block); + custom_keyword!(implementing_type); + custom_keyword!(type_items); + custom_keyword!(fn_items); + custom_keyword!(const_items); } pub struct DeriveImplDef { /// The partial impl block that the user provides. This should be interpreted as "override". - partial_impl_block: syn::ItemImpl, + partial_impl_block: ItemImpl, /// The full path to the type that can be used to receive defaults form. - implementing_type: syn::TypePath, + implementing_type: TypePath, /// All of the associated type items that we must eventually implement. - type_items: Punctuated, + type_items: Punctuated, /// All of the function items that we must eventually implement. - fn_items: Punctuated, + fn_items: Punctuated, /// All of the constant items that we must eventually implement. - const_items: Punctuated, + const_items: Punctuated, } -impl syn::parse::Parse for DeriveImplDef { - fn parse(input: syn::parse::ParseStream) -> Result { +impl Parse for DeriveImplDef { + fn parse(input: ParseStream) -> Result { // NOTE: unfortunately, the order the keywords here must match what the pallet macro // expands. We can probably used a shared set of keywords later. let mut partial_impl_block; let _ = input.parse::()?; - let _ = input.parse::()?; - let _replace_with_bracket: syn::token::Bracket = - syn::bracketed!(partial_impl_block in input); - let _replace_with_brace: syn::token::Brace = - syn::braced!(partial_impl_block in partial_impl_block); + let _ = input.parse::()?; + let _replace_with_bracket: Bracket = bracketed!(partial_impl_block in input); + let _replace_with_brace: Brace = braced!(partial_impl_block in partial_impl_block); let partial_impl_block = partial_impl_block.parse()?; let mut implementing_type; let _ = input.parse::()?; - let _ = input.parse::()?; - let _replace_with_bracket: syn::token::Bracket = - syn::bracketed!(implementing_type in input); - let _replace_with_brace: syn::token::Brace = - syn::braced!(implementing_type in implementing_type); + let _ = input.parse::()?; + let _replace_with_bracket: Bracket = bracketed!(implementing_type in input); + let _replace_with_brace: Brace = braced!(implementing_type in implementing_type); let implementing_type = implementing_type.parse()?; let mut type_items; let _ = input.parse::()?; - let _ = input.parse::()?; - let _replace_with_bracket: syn::token::Bracket = syn::bracketed!(type_items in input); - let _replace_with_brace: syn::token::Brace = syn::braced!(type_items in type_items); - let type_items = Punctuated::::parse_terminated(&type_items)?; + let _ = input.parse::()?; + let _replace_with_bracket: Bracket = bracketed!(type_items in input); + let _replace_with_brace: Brace = braced!(type_items in type_items); + let type_items = Punctuated::::parse_terminated(&type_items)?; let mut fn_items; let _ = input.parse::()?; - let _ = input.parse::()?; - let _replace_with_bracket: syn::token::Bracket = syn::bracketed!(fn_items in input); - let _replace_with_brace: syn::token::Brace = syn::braced!(fn_items in fn_items); - let fn_items = Punctuated::::parse_terminated(&fn_items)?; + let _ = input.parse::()?; + let _replace_with_bracket: Bracket = bracketed!(fn_items in input); + let _replace_with_brace: Brace = braced!(fn_items in fn_items); + let fn_items = Punctuated::::parse_terminated(&fn_items)?; let mut const_items; let _ = input.parse::()?; - let _ = input.parse::()?; - let _replace_with_bracket: syn::token::Bracket = syn::bracketed!(const_items in input); - let _replace_with_brace: syn::token::Brace = syn::braced!(const_items in const_items); - let const_items = Punctuated::::parse_terminated(&const_items)?; + let _ = input.parse::()?; + let _replace_with_bracket: Bracket = bracketed!(const_items in input); + let _replace_with_brace: Brace = braced!(const_items in const_items); + let const_items = Punctuated::::parse_terminated(&const_items)?; Ok(Self { partial_impl_block, type_items, fn_items, const_items, implementing_type }) } @@ -93,11 +97,10 @@ impl syn::parse::Parse for DeriveImplDef { pub(crate) fn derive_impl_inner(input: TokenStream) -> Result { println!("input: {}", input); - let DeriveImplDef { partial_impl_block, implementing_type, type_items, .. } = - syn::parse2(input)?; + let DeriveImplDef { partial_impl_block, implementing_type, type_items, .. } = parse2(input)?; - let type_item_name = |i: &syn::ImplItem| { - if let syn::ImplItem::Type(t) = i { + let type_item_name = |i: &ImplItem| { + if let ImplItem::Type(t) = i { t.ident.clone() } else { panic!("only support type items for now") @@ -125,8 +128,8 @@ pub(crate) fn derive_impl_inner(input: TokenStream) -> Result { } else { // add it let tokens = quote::quote!(type #ident = <#implementing_type as #source_crate_path::pallet::DefaultConfig>::#ident;); - let parsed: syn::ImplItem = syn::parse2(tokens).expect("it is a valid type item"); - debug_assert!(matches!(parsed, syn::ImplItem::Type(_))); + let parsed: ImplItem = parse2(tokens).expect("it is a valid type item"); + debug_assert!(matches!(parsed, ImplItem::Type(_))); final_impl_block.items.push(parsed) } @@ -136,7 +139,7 @@ pub(crate) fn derive_impl_inner(input: TokenStream) -> Result { } pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> Result { - let implementing_type: syn::TypePath = syn::parse2(attrs.clone())?; + let implementing_type: TypePath = parse2(attrs.clone())?; // ideas for sam: // let other_path_tokens = magic_macro!(path_to_other_path_token); // let foreign_trait_def_token: Syn::TraitItem = magic_macro!(frame_system::Config); diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 0c62f9f625594..e2e64296474f0 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -25,6 +25,7 @@ mod construct_runtime; mod crate_version; mod debug_no_bound; mod default_no_bound; +mod derive_impl; mod dummy_part_checker; mod key_prefix; mod match_and_insert; @@ -35,7 +36,6 @@ mod storage; mod storage_alias; mod transactional; mod tt_macro; -mod derive_impl; use proc_macro::TokenStream; use quote::quote; diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index 6bcca96b4e06a..64201cbe9f49f 100644 --- a/frame/support/procedural/src/pallet/expand/config.rs +++ b/frame/support/procedural/src/pallet/expand/config.rs @@ -50,7 +50,8 @@ pub fn expand_config(def: &mut Def) -> proc_macro2::TokenStream { ) .collect::>(); - // we rarely use const and fns in config traits anyways... maybe not supporting them is good enough. + // we rarely use const and fns in config traits anyways... maybe not supporting them is good + // enough. let const_names = Vec::::default(); let fn_names = Vec::::default(); diff --git a/frame/support/procedural/src/pallet/parse/helper.rs b/frame/support/procedural/src/pallet/parse/helper.rs index 0e68e1abc4cbf..05387759fc715 100644 --- a/frame/support/procedural/src/pallet/parse/helper.rs +++ b/frame/support/procedural/src/pallet/parse/helper.rs @@ -47,7 +47,9 @@ pub trait MutItemAttrs { } /// Take the first pallet attribute (e.g. attribute like `#[pallet..]`) and decode it to `Attr` -pub(crate) fn take_first_item_pallet_attr(item: &mut impl MutItemAttrs) -> syn::Result> +pub(crate) fn take_first_item_pallet_attr( + item: &mut impl MutItemAttrs, +) -> syn::Result> where Attr: syn::parse::Parse, { diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 8e1a707d4c60e..f097acee46f93 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -216,7 +216,6 @@ pub use frame_support_procedural::derive_impl; #[doc(hidden)] pub use frame_support_procedural::derive_impl_inner; - /// Create new implementations of the [`Get`](crate::traits::Get) trait. /// /// The so-called parameter type can be created in four different ways: diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 32520ab7553bd..3e1d53256dc72 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -205,8 +205,8 @@ pub mod pallet { use super::*; pub mod testing { type AccountId = u64; - use sp_runtime::traits::IdentityLookup; use super::*; + use sp_runtime::traits::IdentityLookup; pub struct Impl {} impl DefaultConfig for Impl { From 6c6f8c55aa8fb3748bd2134201b8ebe1ff4e0cfd Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 8 Mar 2023 14:48:27 -0500 Subject: [PATCH 009/116] import tokens WIP --- Cargo.lock | 45 +++++++++++++++++++ frame/support/procedural/Cargo.toml | 1 + frame/support/procedural/src/derive_impl.rs | 4 ++ .../procedural/src/pallet/expand/config.rs | 31 ++++++++++--- 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 33bca4005483c..e83da1dcb8083 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -440,6 +440,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" +[[package]] +name = "atomicwrites" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a580bfc0fc2370333eddb71de8c8614d5972e3a327438eb3acc22824a638bf" +dependencies = [ + "rustix", + "tempfile", + "windows-sys 0.45.0", +] + [[package]] name = "atty" version = "0.2.14" @@ -2474,6 +2485,7 @@ dependencies = [ "derive-syn-parse", "frame-support-procedural-tools", "itertools", + "macro_magic", "proc-macro2", "quote", "syn", @@ -4464,6 +4476,39 @@ dependencies = [ "libc", ] +[[package]] +name = "macro_magic" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbbc8ab45e29a7233d828c8cc54947fa19deb63d5bfd47a57f601531dd81a030" +dependencies = [ + "macro_magic_core", + "macro_magic_macros", + "syn", +] + +[[package]] +name = "macro_magic_core" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b2d6342c7e29d670e90de87b60b4b0d11e42d06fcaa43f136019f3d3fea06a" +dependencies = [ + "atomicwrites", + "quote", + "syn", +] + +[[package]] +name = "macro_magic_macros" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f1660de2dfcce670cea4d5e2a79f3a93d6db3a823107fbce10b5e6f0fbf4af" +dependencies = [ + "macro_magic_core", + "quote", + "syn", +] + [[package]] name = "match_cfg" version = "0.1.0" diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index ee1ca4dff8873..4b3381498fda2 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -23,6 +23,7 @@ proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.98", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } +macro_magic = { version = "0.1.5", features = ["indirect"] } [features] default = ["std"] diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index f9b864dc9dbe5..9cf4821bc2ba6 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -18,7 +18,9 @@ //! Implementation of the `derive_impl` attribute macro. use frame_support_procedural_tools::generate_crate_access_2018; +use macro_magic::import_tokens_indirect; use proc_macro2::TokenStream; +use quote::ToTokens; use syn::{ braced, bracketed, parse::{Parse, ParseStream}, @@ -148,6 +150,8 @@ pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> Result proc_macro2::TokenStream { +pub fn expand_config(def: &mut Def) -> TokenStream { let config = &def.config; let config_item = { let item = &mut def.item.content.as_mut().expect("Checked by def parser").1[config.index]; - if let syn::Item::Trait(item) = item { + if let Item::Trait(item) = item { item } else { unreachable!("Checked by config parser") @@ -32,7 +36,7 @@ pub fn expand_config(def: &mut Def) -> proc_macro2::TokenStream { }; if get_doc_literals(&config_item.attrs).is_empty() { - config_item.attrs.push(syn::parse_quote!( + config_item.attrs.push(parse_quote!( #[doc = r" Configuration trait of this pallet. @@ -52,14 +56,29 @@ pub fn expand_config(def: &mut Def) -> proc_macro2::TokenStream { // we rarely use const and fns in config traits anyways... maybe not supporting them is good // enough. - let const_names = Vec::::default(); - let fn_names = Vec::::default(); + let _const_names = Vec::::default(); + let _fn_names = Vec::::default(); - quote::quote!( + // tokens we want to pass to derive_impl, exclude docs + let stripped_config_tokens = quote! { + pub trait Config { + #(#trait_items)* + } + }; + + let Ok((_item, tokens_const_decl)) = export_tokens_internal(stripped_config_tokens, quote!(), "#[pallet::config]") else { + unreachable!("stripped_config_tokens is quoted and thus will parse correctly, QED"); + }; + + quote!( pub trait DefaultConfig { #(#trait_items)* } + #[allow(unused)] + #[doc(hidden)] + #tokens_const_decl + #[macro_export] #[doc(hidden)] // TODO: naming probably needs to be unique From 9abec0a3cb602c5cfbca449a9274736d40dbe2b9 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Mon, 13 Mar 2023 18:43:23 -0400 Subject: [PATCH 010/116] export_tokens working with impl Trait --- Cargo.lock | 15 ++++++++------- frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/src/derive_impl.rs | 3 ++- frame/system/Cargo.toml | 1 + frame/system/src/lib.rs | 3 +++ 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e83da1dcb8083..cda9b9b3d62ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -446,7 +446,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09a580bfc0fc2370333eddb71de8c8614d5972e3a327438eb3acc22824a638bf" dependencies = [ - "rustix", + "rustix 0.36.8", "tempfile", "windows-sys 0.45.0", ] @@ -2564,6 +2564,7 @@ dependencies = [ "criterion", "frame-support", "log", + "macro_magic", "parity-scale-codec", "scale-info", "serde", @@ -4478,9 +4479,9 @@ dependencies = [ [[package]] name = "macro_magic" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbbc8ab45e29a7233d828c8cc54947fa19deb63d5bfd47a57f601531dd81a030" +checksum = "996890480944ead79dde4510dd81c9f90ee0cc3a545bcf925f516c3777dbb9e7" dependencies = [ "macro_magic_core", "macro_magic_macros", @@ -4489,9 +4490,9 @@ dependencies = [ [[package]] name = "macro_magic_core" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b2d6342c7e29d670e90de87b60b4b0d11e42d06fcaa43f136019f3d3fea06a" +checksum = "2474c33425d968d25291a28e90cc237297a3930cad3daaaedf9a5a00b5bc0dfb" dependencies = [ "atomicwrites", "quote", @@ -4500,9 +4501,9 @@ dependencies = [ [[package]] name = "macro_magic_macros" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f1660de2dfcce670cea4d5e2a79f3a93d6db3a823107fbce10b5e6f0fbf4af" +checksum = "f26342b33e4843158619f8926f0214c000f8c03b3b65557ccc826e82d1c51664" dependencies = [ "macro_magic_core", "quote", diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 4b3381498fda2..7b46c76905e1f 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -23,7 +23,7 @@ proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.98", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } -macro_magic = { version = "0.1.5", features = ["indirect"] } +macro_magic = { version = "0.1.6", features = ["indirect"] } [features] default = ["std"] diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 9cf4821bc2ba6..631ebae2b14c4 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -144,7 +144,8 @@ pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> Result Date: Tue, 14 Mar 2023 16:13:10 -0400 Subject: [PATCH 011/116] WIP / notes --- frame/support/procedural/src/derive_impl.rs | 23 +++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 631ebae2b14c4..22116b5d040c2 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -141,22 +141,37 @@ pub(crate) fn derive_impl_inner(input: TokenStream) -> Result { } pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> Result { + // attr: frame_system::preludes::testing::Impl + // tokens: + // impl frame_system::Config for Test { + // // These are all defined by system as mandatory. + // type BaseCallFilter = frame_support::traits::Everything; + // type RuntimeEvent = RuntimeEvent; + // type RuntimeCall = RuntimeCall; + // type RuntimeOrigin = RuntimeOrigin; + // type OnSetCode = frame_system::DefaultSetCode; + // type PalletInfo = PalletInfo; + // type Header = Header; + // // We decide to override this one. + // type AccountData = pallet_balances::AccountData; + // } let implementing_type: TypePath = parse2(attrs.clone())?; // ideas for sam: // let other_path_tokens = magic_macro!(path_to_other_path_token); - let foreign_trait_tokens = import_tokens_indirect!(frame_system::testing::DefaultConfig); - println!("{}", foreign_trait_tokens.to_string()); + // let foreign_trait_tokens = import_tokens_indirect!(frame_system::testing::DefaultConfig); + // println!("{}", foreign_trait_tokens.to_string()); let frame_support = generate_crate_access_2018("frame-support")?; // TODO: may not be accurate. let source_crate_path = implementing_type.path.segments.first().unwrap().ident.clone(); + // source_crate_path = frame_system //let tokens = import_tokens_indirect!(::pallet_example_basic::pallet::Config); Ok(quote::quote!( #frame_support::tt_call! { - macro = [{ #source_crate_path::tt_config_items }] - frame_support = [{ #frame_support }] + macro = [{ #source_crate_path::tt_config_items }] // frame_system::tt_config_items + frame_support = [{ #frame_support }] // ::frame_support ~~> #frame_support::derive_impl_inner! { partial_impl_block = [{ #input }] implementing_type = [{ #attrs }] From 01c88add93fa91dd266fc1687941c2533be65db0 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 24 Mar 2023 01:34:53 -0400 Subject: [PATCH 012/116] use macro_magic 0.2.0's export_tokens to access foreign items --- Cargo.lock | 45 +++++++++++-------- frame/support/Cargo.toml | 1 + frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/src/derive_impl.rs | 2 +- .../procedural/src/pallet/expand/config.rs | 21 +++------ frame/support/src/lib.rs | 5 +++ frame/system/Cargo.toml | 2 +- frame/system/src/lib.rs | 2 +- 8 files changed, 43 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cda9b9b3d62ba..ba3f57e07f5da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -440,17 +440,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" -[[package]] -name = "atomicwrites" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a580bfc0fc2370333eddb71de8c8614d5972e3a327438eb3acc22824a638bf" -dependencies = [ - "rustix 0.36.8", - "tempfile", - "windows-sys 0.45.0", -] - [[package]] name = "atty" version = "0.2.14" @@ -1126,6 +1115,15 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -2453,6 +2451,7 @@ dependencies = [ "impl-trait-for-tuples", "k256", "log", + "macro_magic", "once_cell", "parity-scale-codec", "paste", @@ -4479,31 +4478,35 @@ dependencies = [ [[package]] name = "macro_magic" -version = "0.1.6" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "996890480944ead79dde4510dd81c9f90ee0cc3a545bcf925f516c3777dbb9e7" +checksum = "1a46cb4aa5d8f8ed2dff8aabb1897057dcf2226010e4c113f0a5ba18b6aceca3" dependencies = [ "macro_magic_core", "macro_magic_macros", + "quote", "syn", ] [[package]] name = "macro_magic_core" -version = "0.1.6" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2474c33425d968d25291a28e90cc237297a3930cad3daaaedf9a5a00b5bc0dfb" +checksum = "adfee80cffea890d40db7f6fcab74dfa8be40ed9c0be33dc0d23de360a625107" dependencies = [ - "atomicwrites", + "convert_case", + "derive-syn-parse", + "prettyplease", + "proc-macro2", "quote", "syn", ] [[package]] name = "macro_magic_macros" -version = "0.1.6" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26342b33e4843158619f8926f0214c000f8c03b3b65557ccc826e82d1c51664" +checksum = "3e52f768d6f74458b01f841fcf0423135895ed44032d1b100fb2f17111fe397f" dependencies = [ "macro_magic_core", "quote", @@ -12088,6 +12091,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-width" version = "0.1.10" diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 820658372afd9..8a7fbe33f33e7 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -28,6 +28,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } tt-call = "1.0.8" +macro_magic = "0.2.0" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 7b46c76905e1f..6c550538be742 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -23,7 +23,7 @@ proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.98", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } -macro_magic = { version = "0.1.6", features = ["indirect"] } +macro_magic = "0.2.0" [features] default = ["std"] diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 22116b5d040c2..540f9ecc12405 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -18,7 +18,7 @@ //! Implementation of the `derive_impl` attribute macro. use frame_support_procedural_tools::generate_crate_access_2018; -use macro_magic::import_tokens_indirect; +use macro_magic::import_tokens_attr; use proc_macro2::TokenStream; use quote::ToTokens; use syn::{ diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index fd53466789bf7..6622bee8984bb 100644 --- a/frame/support/procedural/src/pallet/expand/config.rs +++ b/frame/support/procedural/src/pallet/expand/config.rs @@ -16,8 +16,7 @@ // limitations under the License. use crate::pallet::Def; -use frame_support_procedural_tools::get_doc_literals; -use macro_magic::core::export_tokens_internal; +use frame_support_procedural_tools::{generate_crate_access_2018, get_doc_literals}; use proc_macro2::TokenStream; use quote::quote; use syn::{parse_quote, Item}; @@ -59,26 +58,18 @@ pub fn expand_config(def: &mut Def) -> TokenStream { let _const_names = Vec::::default(); let _fn_names = Vec::::default(); - // tokens we want to pass to derive_impl, exclude docs - let stripped_config_tokens = quote! { - pub trait Config { - #(#trait_items)* - } - }; - - let Ok((_item, tokens_const_decl)) = export_tokens_internal(stripped_config_tokens, quote!(), "#[pallet::config]") else { - unreachable!("stripped_config_tokens is quoted and thus will parse correctly, QED"); + // get reference to frame_support + let support = match generate_crate_access_2018("frame-support") { + Ok(krate) => krate, + Err(err) => return err.to_compile_error(), }; quote!( + #[#support::macro_magic::export_tokens] pub trait DefaultConfig { #(#trait_items)* } - #[allow(unused)] - #[doc(hidden)] - #tokens_const_decl - #[macro_export] #[doc(hidden)] // TODO: naming probably needs to be unique diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index f097acee46f93..9ee9588f15393 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -829,6 +829,11 @@ macro_rules! assert_error_encoded_size { #[doc(hidden)] pub use serde::{Deserialize, Serialize}; +#[doc(hidden)] +pub mod macro_magic { + pub use ::macro_magic::*; +} + #[cfg(test)] pub mod tests { use super::*; diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 7d7d1cc943060..4938495228d94 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -macro_magic = { version = "0.1.6", features = ["indirect-write"] } +macro_magic = "0.2.0" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 7803d3afca7b5..df349b94e4a7c 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -211,7 +211,7 @@ pub mod pallet { pub struct Impl {} - #[export_tokens(frame_system::testing::DefaultConfig)] + #[export_tokens(testing_DefaultConfig)] impl DefaultConfig for Impl { type Version = (); type BlockWeights = (); From 4b481bea638367f9ace79dd3a93e64c74b0016e4 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 28 Mar 2023 01:35:28 -0400 Subject: [PATCH 013/116] token importing working properly using macro_magic 0.2.5 --- Cargo.lock | 25 ++++++++++++++++----- frame/examples/basic/Cargo.toml | 1 + frame/examples/basic/src/tests.rs | 8 +++++-- frame/support/.cargo/config.toml | 2 ++ frame/support/Cargo.toml | 2 +- frame/support/procedural/.cargo/config.toml | 2 ++ frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/src/derive_impl.rs | 4 +++- frame/support/procedural/src/lib.rs | 4 +++- frame/support/src/lib.rs | 5 ++++- frame/system/Cargo.toml | 2 +- frame/system/src/lib.rs | 2 +- 12 files changed, 44 insertions(+), 15 deletions(-) create mode 100644 frame/support/.cargo/config.toml create mode 100644 frame/support/procedural/.cargo/config.toml diff --git a/Cargo.lock b/Cargo.lock index ba3f57e07f5da..be934ad6e849c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4478,9 +4478,9 @@ dependencies = [ [[package]] name = "macro_magic" -version = "0.2.0" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a46cb4aa5d8f8ed2dff8aabb1897057dcf2226010e4c113f0a5ba18b6aceca3" +checksum = "0b99f8208e778933c757f131dbdcf7a93342718b2128593b8186f1242844177c" dependencies = [ "macro_magic_core", "macro_magic_macros", @@ -4490,23 +4490,35 @@ dependencies = [ [[package]] name = "macro_magic_core" -version = "0.2.0" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adfee80cffea890d40db7f6fcab74dfa8be40ed9c0be33dc0d23de360a625107" +checksum = "194cce8673866a9f5834c4f14504d446007666ca39ae1556711e195d425c5518" dependencies = [ "convert_case", "derive-syn-parse", + "macro_magic_core_macros", "prettyplease", "proc-macro2", "quote", "syn", ] +[[package]] +name = "macro_magic_core_macros" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1e4637d501823b6a68001cba03d2cf437ec108495fa20cd9eec300a3717950" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "macro_magic_macros" -version = "0.2.0" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e52f768d6f74458b01f841fcf0423135895ed44032d1b100fb2f17111fe397f" +checksum = "38e2193937cbecce1e6d37ad2558718eab2dd9ed71c3756a95e07331714bb0b8" dependencies = [ "macro_magic_core", "quote", @@ -6064,6 +6076,7 @@ dependencies = [ "frame-support", "frame-system", "log", + "macro_magic", "pallet-balances", "parity-scale-codec", "scale-info", diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index 2f854011b0abd..5f1127435d23b 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -23,6 +23,7 @@ pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../ sp-io = { version = "7.0.0", default-features = false, path = "../../../primitives/io" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } +macro_magic = "0.2.5" [dev-dependencies] sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index ff9b8fd7f7ff7..4a0f0fa02c32b 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -19,8 +19,9 @@ use crate::*; use frame_support::{ - assert_ok, + assert_ok, derive_impl_inner, dispatch::{DispatchInfo, GetDispatchInfo}, + macro_magic::*, traits::{ConstU64, OnInitialize}, }; use sp_core::H256; @@ -34,6 +35,9 @@ use sp_runtime::{ // Reexport crate as its pallet name for construct_runtime. use crate as pallet_example_basic; +#[use_attr] +use frame_support::derive_impl; + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -50,7 +54,7 @@ frame_support::construct_runtime!( } ); -#[frame_support::derive_impl(frame_system::preludes::testing::Impl)] +#[derive_impl(frame_system::preludes::testing::TestDefaultConfig)] impl frame_system::Config for Test { // These are all defined by system as mandatory. type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/support/.cargo/config.toml b/frame/support/.cargo/config.toml new file mode 100644 index 0000000000000..aade7e3ac5723 --- /dev/null +++ b/frame/support/.cargo/config.toml @@ -0,0 +1,2 @@ +[env] +# MACRO_MAGIC_ROOT= "::frame_support::macro_magic" diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 8a7fbe33f33e7..85251a7c04618 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -28,7 +28,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } tt-call = "1.0.8" -macro_magic = "0.2.0" +macro_magic = "0.2.5" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } diff --git a/frame/support/procedural/.cargo/config.toml b/frame/support/procedural/.cargo/config.toml new file mode 100644 index 0000000000000..2959e05d1943f --- /dev/null +++ b/frame/support/procedural/.cargo/config.toml @@ -0,0 +1,2 @@ +[env] +# MACRO_MAGIC_ROOT = { value = "::macro_magic", force = true } diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 6c550538be742..2caf789e83a02 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -23,7 +23,7 @@ proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.98", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } -macro_magic = "0.2.0" +macro_magic = "0.2.5" [features] default = ["std"] diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 540f9ecc12405..5f0b53a4b3570 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -18,7 +18,6 @@ //! Implementation of the `derive_impl` attribute macro. use frame_support_procedural_tools::generate_crate_access_2018; -use macro_magic::import_tokens_attr; use proc_macro2::TokenStream; use quote::ToTokens; use syn::{ @@ -141,6 +140,9 @@ pub(crate) fn derive_impl_inner(input: TokenStream) -> Result { } pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> Result { + let foreign_impl = parse2::(attrs.clone())?; + println!("FOREIGN IMPL:: {}", foreign_impl.to_token_stream().to_string()); + panic!("stop here"); // attr: frame_system::preludes::testing::Impl // tokens: // impl frame_system::Config for Test { diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index e2e64296474f0..1bf82d28c6c43 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -37,8 +37,9 @@ mod storage_alias; mod transactional; mod tt_macro; +use macro_magic::import_tokens_attr; use proc_macro::TokenStream; -use quote::quote; +use quote::{quote, ToTokens}; use std::{cell::RefCell, str::FromStr}; pub(crate) use storage::INHERENT_INSTANCE_NAME; @@ -777,6 +778,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { .into() } +#[import_tokens_attr] #[proc_macro_attribute] pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { derive_impl::derive_impl(attrs.into(), input.into()) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 9ee9588f15393..ff8f9fbf5be05 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -32,6 +32,7 @@ /// Export ourself as `frame_support` to make tests happy. extern crate self as frame_support; +use ::macro_magic::use_attr; #[doc(hidden)] pub use sp_tracing; @@ -211,8 +212,10 @@ impl TypeId for PalletId { /// ``` pub use frame_support_procedural::storage_alias; -/// FOOO +/// Test +#[use_attr] pub use frame_support_procedural::derive_impl; + #[doc(hidden)] pub use frame_support_procedural::derive_impl_inner; diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 4938495228d94..679bbd8f7fcf1 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -macro_magic = "0.2.0" +macro_magic = "0.2.5" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index df349b94e4a7c..e53de29531943 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -211,7 +211,7 @@ pub mod pallet { pub struct Impl {} - #[export_tokens(testing_DefaultConfig)] + #[export_tokens(TestDefaultConfig)] impl DefaultConfig for Impl { type Version = (); type BlockWeights = (); From 4ff18f46678a02bb102285ae85786659b31cec13 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 28 Mar 2023 17:37:43 -0400 Subject: [PATCH 014/116] combine_impls almost working --- frame/examples/basic/src/tests.rs | 2 +- frame/support/procedural/src/derive_impl.rs | 121 +++++++++++++++----- frame/system/src/lib.rs | 2 +- 3 files changed, 95 insertions(+), 30 deletions(-) diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 4a0f0fa02c32b..b19cdf6e4bd3a 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -21,7 +21,7 @@ use crate::*; use frame_support::{ assert_ok, derive_impl_inner, dispatch::{DispatchInfo, GetDispatchInfo}, - macro_magic::*, + macro_magic::use_attr, traits::{ConstU64, OnInitialize}, }; use sp_core::H256; diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 5f0b53a4b3570..2f3ac2e814dd9 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -17,9 +17,12 @@ //! Implementation of the `derive_impl` attribute macro. +use std::collections::{HashMap, HashSet}; + use frame_support_procedural_tools::generate_crate_access_2018; +use macro_magic::core::pretty_print; use proc_macro2::TokenStream; -use quote::ToTokens; +use quote::{quote, ToTokens}; use syn::{ braced, bracketed, parse::{Parse, ParseStream}, @@ -139,10 +142,72 @@ pub(crate) fn derive_impl_inner(input: TokenStream) -> Result { Ok(quote::quote!(#final_impl_block)) } -pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> Result { - let foreign_impl = parse2::(attrs.clone())?; - println!("FOREIGN IMPL:: {}", foreign_impl.to_token_stream().to_string()); - panic!("stop here"); +fn impl_item_ident(impl_item: &ImplItem) -> Option { + match impl_item { + ImplItem::Const(item) => Some(item.ident.clone()), + ImplItem::Method(item) => Some(item.sig.ident.clone()), + ImplItem::Type(item) => Some(item.ident.clone()), + _ => None, + } +} + +fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl) -> ItemImpl { + let existing_local_keys: HashSet = local_impl + .items + .iter() + .filter_map(|impl_item| impl_item_ident(impl_item)) + .collect(); + let existing_unsupported_items: HashSet = local_impl + .items + .iter() + .filter(|impl_item| impl_item_ident(impl_item).is_none()) + .cloned() + .collect(); + let mut final_impl = local_impl; + final_impl.items.extend( + foreign_impl + .items + .iter() + .filter_map(|item| { + if let Some(ident) = impl_item_ident(&item) { + if existing_local_keys.contains(&ident) { + // do not copy colliding supported items + None + } else { + // copy uncolliding supported items verbatim + Some(item) + } + } else { + if existing_unsupported_items.contains(item) { + // do not copy colliding unsupported items + None + } else { + // copy uncolliding unsupported items + Some(item) + } + } + }) + .cloned() + .collect::>(), + ); + final_impl +} + +pub fn derive_impl(foreign_tokens: TokenStream, local_tokens: TokenStream) -> Result { + let local_impl = parse2::(local_tokens)?; + let foreign_impl = parse2::(foreign_tokens)?; + + println!("\nlocal_impl:"); + pretty_print(&local_impl.to_token_stream()); + println!("foreign_impl:"); + pretty_print(&foreign_impl.to_token_stream()); + + let combined_impl = combine_impls(local_impl, foreign_impl); + + println!("combined_impl:"); + pretty_print(&combined_impl.to_token_stream()); + + Ok(quote!(#combined_impl)) // attr: frame_system::preludes::testing::Impl // tokens: // impl frame_system::Config for Test { @@ -157,27 +222,27 @@ pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> Result; // } - let implementing_type: TypePath = parse2(attrs.clone())?; - // ideas for sam: - // let other_path_tokens = magic_macro!(path_to_other_path_token); - // let foreign_trait_tokens = import_tokens_indirect!(frame_system::testing::DefaultConfig); - // println!("{}", foreign_trait_tokens.to_string()); - - let frame_support = generate_crate_access_2018("frame-support")?; - // TODO: may not be accurate. - let source_crate_path = implementing_type.path.segments.first().unwrap().ident.clone(); - // source_crate_path = frame_system - - //let tokens = import_tokens_indirect!(::pallet_example_basic::pallet::Config); - - Ok(quote::quote!( - #frame_support::tt_call! { - macro = [{ #source_crate_path::tt_config_items }] // frame_system::tt_config_items - frame_support = [{ #frame_support }] // ::frame_support - ~~> #frame_support::derive_impl_inner! { - partial_impl_block = [{ #input }] - implementing_type = [{ #attrs }] - } - } - )) + // let implementing_type: TypePath = parse2(attrs.clone())?; + // // ideas for sam: + // // let other_path_tokens = magic_macro!(path_to_other_path_token); + // // let foreign_trait_tokens = import_tokens_indirect!(frame_system::testing::DefaultConfig); + // // println!("{}", foreign_trait_tokens.to_string()); + + // let frame_support = generate_crate_access_2018("frame-support")?; + // // TODO: may not be accurate. + // let source_crate_path = implementing_type.path.segments.first().unwrap().ident.clone(); + // // source_crate_path = frame_system + + // //let tokens = import_tokens_indirect!(::pallet_example_basic::pallet::Config); + + // Ok(quote::quote!( + // #frame_support::tt_call! { + // macro = [{ #source_crate_path::tt_config_items }] // frame_system::tt_config_items + // frame_support = [{ #frame_support }] // ::frame_support + // ~~> #frame_support::derive_impl_inner! { + // partial_impl_block = [{ #input }] + // implementing_type = [{ #attrs }] + // } + // } + // )) } diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index e53de29531943..083986a85cbc8 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -229,7 +229,7 @@ pub mod pallet { type OnKilledAccount = (); type SystemWeightInfo = (); type SS58Prefix = (); - type MaxConsumers = ConstU32<16>; + type MaxConsumers = frame_support::traits::ConstU32<16>; } } } From cd0753cb2581de3ef00e35039e3e9ef09a8e5075 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 29 Mar 2023 00:45:32 -0400 Subject: [PATCH 015/116] successfully get foreign path via macro_magic 0.2.6 --- Cargo.lock | 16 ++++++++-------- frame/examples/basic/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/src/derive_impl.rs | 3 ++- frame/support/procedural/src/lib.rs | 2 +- frame/system/Cargo.toml | 2 +- 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be934ad6e849c..99085a5d15229 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4478,9 +4478,9 @@ dependencies = [ [[package]] name = "macro_magic" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b99f8208e778933c757f131dbdcf7a93342718b2128593b8186f1242844177c" +checksum = "b745dd26139d33d0c29799b8983eda0673e5e30613f9b3a42743c146c4bd887a" dependencies = [ "macro_magic_core", "macro_magic_macros", @@ -4490,9 +4490,9 @@ dependencies = [ [[package]] name = "macro_magic_core" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194cce8673866a9f5834c4f14504d446007666ca39ae1556711e195d425c5518" +checksum = "b432f14f3e7100d45a36576b2acaa7f246cac3a0d3221715d9f16355a154838a" dependencies = [ "convert_case", "derive-syn-parse", @@ -4505,9 +4505,9 @@ dependencies = [ [[package]] name = "macro_magic_core_macros" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1e4637d501823b6a68001cba03d2cf437ec108495fa20cd9eec300a3717950" +checksum = "809c2526d4dfc5b3f30a6b80b45a5fcf1f15cabe4fb1094bc9c1d8e1857c7f35" dependencies = [ "proc-macro2", "quote", @@ -4516,9 +4516,9 @@ dependencies = [ [[package]] name = "macro_magic_macros" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2193937cbecce1e6d37ad2558718eab2dd9ed71c3756a95e07331714bb0b8" +checksum = "ccabbd32376feddaaed042c928a93368f6e1a0274d339857c379e43339e3daee" dependencies = [ "macro_magic_core", "quote", diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index 5f1127435d23b..471dda86d8fdb 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -23,7 +23,7 @@ pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../ sp-io = { version = "7.0.0", default-features = false, path = "../../../primitives/io" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } -macro_magic = "0.2.5" +macro_magic = "0.2.6" [dev-dependencies] sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 85251a7c04618..73a855cbc0211 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -28,7 +28,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } tt-call = "1.0.8" -macro_magic = "0.2.5" +macro_magic = "0.2.6" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 2caf789e83a02..9e4bc7858dfcd 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -23,7 +23,7 @@ proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.98", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } -macro_magic = "0.2.5" +macro_magic = "0.2.6" [features] default = ["std"] diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 2f3ac2e814dd9..97060a922b8d6 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -193,7 +193,7 @@ fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl) -> ItemImpl { final_impl } -pub fn derive_impl(foreign_tokens: TokenStream, local_tokens: TokenStream) -> Result { +pub fn derive_impl(foreign_path: TokenStream, foreign_tokens: TokenStream, local_tokens: TokenStream) -> Result { let local_impl = parse2::(local_tokens)?; let foreign_impl = parse2::(foreign_tokens)?; @@ -201,6 +201,7 @@ pub fn derive_impl(foreign_tokens: TokenStream, local_tokens: TokenStream) -> Re pretty_print(&local_impl.to_token_stream()); println!("foreign_impl:"); pretty_print(&foreign_impl.to_token_stream()); + println!("foreign_path: {}", foreign_path); let combined_impl = combine_impls(local_impl, foreign_impl); diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 1bf82d28c6c43..2df8017d74997 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -781,7 +781,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { #[import_tokens_attr] #[proc_macro_attribute] pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { - derive_impl::derive_impl(attrs.into(), input.into()) + derive_impl::derive_impl(__source_path.into(), attrs.into(), input.into()) .unwrap_or_else(|r| r.into_compile_error()) .into() } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 679bbd8f7fcf1..23c175efc292a 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -macro_magic = "0.2.5" +macro_magic = "0.2.6" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } From 07d80f5d3cb227469954e9b973aac219018e49b1 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 29 Mar 2023 02:05:34 -0400 Subject: [PATCH 016/116] combine_impls using implementing_type generics --- frame/support/procedural/src/derive_impl.rs | 59 ++++++++++++--------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 97060a922b8d6..0434734d8f105 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -17,19 +17,17 @@ //! Implementation of the `derive_impl` attribute macro. -use std::collections::{HashMap, HashSet}; - -use frame_support_procedural_tools::generate_crate_access_2018; use macro_magic::core::pretty_print; -use proc_macro2::TokenStream; +use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens}; +use std::collections::HashSet; use syn::{ braced, bracketed, parse::{Parse, ParseStream}, - parse2, + parse2, parse_quote, punctuated::Punctuated, token::{Brace, Bracket}, - Ident, ImplItem, ItemImpl, Result, Token, TypePath, + Ident, ImplItem, ItemImpl, Path, Result, Token, TypePath, }; mod keywords { @@ -99,7 +97,7 @@ impl Parse for DeriveImplDef { } } -pub(crate) fn derive_impl_inner(input: TokenStream) -> Result { +pub(crate) fn derive_impl_inner(input: TokenStream2) -> Result { println!("input: {}", input); let DeriveImplDef { partial_impl_block, implementing_type, type_items, .. } = parse2(input)?; @@ -151,7 +149,7 @@ fn impl_item_ident(impl_item: &ImplItem) -> Option { } } -fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl) -> ItemImpl { +fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl, foreign_path: Path) -> ItemImpl { let existing_local_keys: HashSet = local_impl .items .iter() @@ -163,47 +161,60 @@ fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl) -> ItemImpl { .filter(|impl_item| impl_item_ident(impl_item).is_none()) .cloned() .collect(); + let source_crate_path = foreign_path.segments.first().unwrap().ident.clone(); let mut final_impl = local_impl; final_impl.items.extend( foreign_impl .items - .iter() + .into_iter() .filter_map(|item| { if let Some(ident) = impl_item_ident(&item) { if existing_local_keys.contains(&ident) { - // do not copy colliding supported items + // do not copy colliding items that have an ident None } else { - // copy uncolliding supported items verbatim - Some(item) + if matches!(item, ImplItem::Type(_)) { + // modify and insert uncolliding type items + let modified_item: ImplItem = parse_quote! { + type #ident = <#foreign_path as #source_crate_path::pallet::DefaultConfig>::#ident; + }; + Some(modified_item) + } else { + // copy uncolliding non-type items that have an ident + Some(item) + } } } else { - if existing_unsupported_items.contains(item) { - // do not copy colliding unsupported items + if existing_unsupported_items.contains(&item) { + // do not copy colliding items that lack an ident None } else { - // copy uncolliding unsupported items + // copy uncolliding items without an ident verbaitm Some(item) } } }) - .cloned() .collect::>(), ); final_impl } -pub fn derive_impl(foreign_path: TokenStream, foreign_tokens: TokenStream, local_tokens: TokenStream) -> Result { +pub fn derive_impl( + foreign_path: TokenStream2, + foreign_tokens: TokenStream2, + local_tokens: TokenStream2, +) -> Result { + println!("foreign_path: {}\n", foreign_path.to_string()); + println!("foreign_impl:"); + pretty_print(&foreign_tokens); + println!("\nlocal_impl:"); + pretty_print(&local_tokens); + let local_impl = parse2::(local_tokens)?; let foreign_impl = parse2::(foreign_tokens)?; + let foreign_path = parse2::(foreign_path)?; - println!("\nlocal_impl:"); - pretty_print(&local_impl.to_token_stream()); - println!("foreign_impl:"); - pretty_print(&foreign_impl.to_token_stream()); - println!("foreign_path: {}", foreign_path); - - let combined_impl = combine_impls(local_impl, foreign_impl); + let combined_impl = combine_impls(local_impl, foreign_impl, foreign_path); println!("combined_impl:"); pretty_print(&combined_impl.to_token_stream()); From 7dc80229a081d475a87f4433e8f904ee52069565 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 29 Mar 2023 02:28:58 -0400 Subject: [PATCH 017/116] working + clean up --- frame/examples/basic/src/tests.rs | 10 +- frame/support/procedural/src/derive_impl.rs | 158 +------------------- frame/support/procedural/src/lib.rs | 7 - frame/support/src/lib.rs | 4 - frame/system/src/lib.rs | 4 +- 5 files changed, 8 insertions(+), 175 deletions(-) diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index b19cdf6e4bd3a..4827eda5ad84a 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -19,19 +19,15 @@ use crate::*; use frame_support::{ - assert_ok, derive_impl_inner, + assert_ok, dispatch::{DispatchInfo, GetDispatchInfo}, macro_magic::use_attr, traits::{ConstU64, OnInitialize}, }; -use sp_core::H256; + // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::{testing::Header, BuildStorage}; // Reexport crate as its pallet name for construct_runtime. use crate as pallet_example_basic; diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 0434734d8f105..bc6cea9f61418 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -21,124 +21,7 @@ use macro_magic::core::pretty_print; use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens}; use std::collections::HashSet; -use syn::{ - braced, bracketed, - parse::{Parse, ParseStream}, - parse2, parse_quote, - punctuated::Punctuated, - token::{Brace, Bracket}, - Ident, ImplItem, ItemImpl, Path, Result, Token, TypePath, -}; - -mod keywords { - use syn::custom_keyword; - - custom_keyword!(derive_impl); - custom_keyword!(partial_impl_block); - custom_keyword!(implementing_type); - custom_keyword!(type_items); - custom_keyword!(fn_items); - custom_keyword!(const_items); -} - -pub struct DeriveImplDef { - /// The partial impl block that the user provides. This should be interpreted as "override". - partial_impl_block: ItemImpl, - /// The full path to the type that can be used to receive defaults form. - implementing_type: TypePath, - /// All of the associated type items that we must eventually implement. - type_items: Punctuated, - /// All of the function items that we must eventually implement. - fn_items: Punctuated, - /// All of the constant items that we must eventually implement. - const_items: Punctuated, -} - -impl Parse for DeriveImplDef { - fn parse(input: ParseStream) -> Result { - // NOTE: unfortunately, the order the keywords here must match what the pallet macro - // expands. We can probably used a shared set of keywords later. - let mut partial_impl_block; - let _ = input.parse::()?; - let _ = input.parse::()?; - let _replace_with_bracket: Bracket = bracketed!(partial_impl_block in input); - let _replace_with_brace: Brace = braced!(partial_impl_block in partial_impl_block); - let partial_impl_block = partial_impl_block.parse()?; - - let mut implementing_type; - let _ = input.parse::()?; - let _ = input.parse::()?; - let _replace_with_bracket: Bracket = bracketed!(implementing_type in input); - let _replace_with_brace: Brace = braced!(implementing_type in implementing_type); - let implementing_type = implementing_type.parse()?; - - let mut type_items; - let _ = input.parse::()?; - let _ = input.parse::()?; - let _replace_with_bracket: Bracket = bracketed!(type_items in input); - let _replace_with_brace: Brace = braced!(type_items in type_items); - let type_items = Punctuated::::parse_terminated(&type_items)?; - - let mut fn_items; - let _ = input.parse::()?; - let _ = input.parse::()?; - let _replace_with_bracket: Bracket = bracketed!(fn_items in input); - let _replace_with_brace: Brace = braced!(fn_items in fn_items); - let fn_items = Punctuated::::parse_terminated(&fn_items)?; - - let mut const_items; - let _ = input.parse::()?; - let _ = input.parse::()?; - let _replace_with_bracket: Bracket = bracketed!(const_items in input); - let _replace_with_brace: Brace = braced!(const_items in const_items); - let const_items = Punctuated::::parse_terminated(&const_items)?; - - Ok(Self { partial_impl_block, type_items, fn_items, const_items, implementing_type }) - } -} - -pub(crate) fn derive_impl_inner(input: TokenStream2) -> Result { - println!("input: {}", input); - let DeriveImplDef { partial_impl_block, implementing_type, type_items, .. } = parse2(input)?; - - let type_item_name = |i: &ImplItem| { - if let ImplItem::Type(t) = i { - t.ident.clone() - } else { - panic!("only support type items for now") - } - }; - - // might be able to mutate `partial_impl_block` along the way, but easier like this for now. - let mut final_impl_block = partial_impl_block.clone(); - let source_crate_path = implementing_type.path.segments.first().unwrap().ident.clone(); - - // TODO: ensure type ident specified in `partial_impl_block` is beyond union(type_items, - // const_items, fn_items). - assert!( - partial_impl_block - .items - .iter() - .all(|i| { type_items.iter().find(|tt| tt == &&type_item_name(i)).is_some() }), - "some item in the partial_impl_block is unexpected" - ); - - // for each item that is in `type_items` but not present in `partial_impl_block`, fill it in. - type_items.iter().for_each(|ident| { - if partial_impl_block.items.iter().any(|i| &type_item_name(i) == ident) { - // this is already present in the partial impl block -- noop - } else { - // add it - let tokens = quote::quote!(type #ident = <#implementing_type as #source_crate_path::pallet::DefaultConfig>::#ident;); - let parsed: ImplItem = parse2(tokens).expect("it is a valid type item"); - debug_assert!(matches!(parsed, ImplItem::Type(_))); - - final_impl_block.items.push(parsed) - } - }); - - Ok(quote::quote!(#final_impl_block)) -} +use syn::{parse2, parse_quote, Ident, ImplItem, ItemImpl, Path, Result}; fn impl_item_ident(impl_item: &ImplItem) -> Option { match impl_item { @@ -161,6 +44,8 @@ fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl, foreign_path: Pat .filter(|impl_item| impl_item_ident(impl_item).is_none()) .cloned() .collect(); + // // TODO: may not be accurate. + // // source_crate_path = frame_system let source_crate_path = foreign_path.segments.first().unwrap().ident.clone(); let mut final_impl = local_impl; final_impl.items.extend( @@ -220,41 +105,4 @@ pub fn derive_impl( pretty_print(&combined_impl.to_token_stream()); Ok(quote!(#combined_impl)) - // attr: frame_system::preludes::testing::Impl - // tokens: - // impl frame_system::Config for Test { - // // These are all defined by system as mandatory. - // type BaseCallFilter = frame_support::traits::Everything; - // type RuntimeEvent = RuntimeEvent; - // type RuntimeCall = RuntimeCall; - // type RuntimeOrigin = RuntimeOrigin; - // type OnSetCode = frame_system::DefaultSetCode; - // type PalletInfo = PalletInfo; - // type Header = Header; - // // We decide to override this one. - // type AccountData = pallet_balances::AccountData; - // } - // let implementing_type: TypePath = parse2(attrs.clone())?; - // // ideas for sam: - // // let other_path_tokens = magic_macro!(path_to_other_path_token); - // // let foreign_trait_tokens = import_tokens_indirect!(frame_system::testing::DefaultConfig); - // // println!("{}", foreign_trait_tokens.to_string()); - - // let frame_support = generate_crate_access_2018("frame-support")?; - // // TODO: may not be accurate. - // let source_crate_path = implementing_type.path.segments.first().unwrap().ident.clone(); - // // source_crate_path = frame_system - - // //let tokens = import_tokens_indirect!(::pallet_example_basic::pallet::Config); - - // Ok(quote::quote!( - // #frame_support::tt_call! { - // macro = [{ #source_crate_path::tt_config_items }] // frame_system::tt_config_items - // frame_support = [{ #frame_support }] // ::frame_support - // ~~> #frame_support::derive_impl_inner! { - // partial_impl_block = [{ #input }] - // implementing_type = [{ #attrs }] - // } - // } - // )) } diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 2df8017d74997..3accbb23dcf8d 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -786,13 +786,6 @@ pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { .into() } -#[proc_macro] -pub fn derive_impl_inner(input: TokenStream) -> TokenStream { - derive_impl::derive_impl_inner(input.into()) - .unwrap_or_else(|r| r.into_compile_error()) - .into() -} - /// Used internally to decorate pallet attribute macro stubs when they are erroneously used /// outside of a pallet module fn pallet_macro_stub() -> TokenStream { diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index ff8f9fbf5be05..f8c31f0aeac38 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -212,13 +212,9 @@ impl TypeId for PalletId { /// ``` pub use frame_support_procedural::storage_alias; -/// Test #[use_attr] pub use frame_support_procedural::derive_impl; -#[doc(hidden)] -pub use frame_support_procedural::derive_impl_inner; - /// Create new implementations of the [`Get`](crate::traits::Get) trait. /// /// The so-called parameter type can be created in four different ways: diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 083986a85cbc8..3f6d2274a0bcb 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -209,10 +209,10 @@ pub mod pallet { use macro_magic::export_tokens; use sp_runtime::traits::IdentityLookup; - pub struct Impl {} + pub struct TestDefaultConfig {} #[export_tokens(TestDefaultConfig)] - impl DefaultConfig for Impl { + impl DefaultConfig for TestDefaultConfig { type Version = (); type BlockWeights = (); type BlockLength = (); From c8924cce4b162e509f0501b12a75e57872e36c4a Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 29 Mar 2023 02:30:27 -0400 Subject: [PATCH 018/116] more clean up --- frame/support/.cargo/config.toml | 2 -- frame/support/procedural/.cargo/config.toml | 2 -- 2 files changed, 4 deletions(-) delete mode 100644 frame/support/.cargo/config.toml delete mode 100644 frame/support/procedural/.cargo/config.toml diff --git a/frame/support/.cargo/config.toml b/frame/support/.cargo/config.toml deleted file mode 100644 index aade7e3ac5723..0000000000000 --- a/frame/support/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[env] -# MACRO_MAGIC_ROOT= "::frame_support::macro_magic" diff --git a/frame/support/procedural/.cargo/config.toml b/frame/support/procedural/.cargo/config.toml deleted file mode 100644 index 2959e05d1943f..0000000000000 --- a/frame/support/procedural/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[env] -# MACRO_MAGIC_ROOT = { value = "::macro_magic", force = true } From b409576c2f95929d33b590a8a22bc88b617cb9a4 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 29 Mar 2023 12:38:40 -0400 Subject: [PATCH 019/116] decrease rightwards drift and add docs to combine_impls --- frame/support/procedural/src/derive_impl.rs | 69 ++++++++++++--------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index bc6cea9f61418..33bf2e6c96362 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -32,6 +32,18 @@ fn impl_item_ident(impl_item: &ImplItem) -> Option { } } +/// The real meat behind `derive_impl`. Takes in a `local_impl`, which is the impl for which we +/// want to implement defaults (i.e. the one the attribute macro is attached to), and a +/// `foreign_impl`, which is the impl containing the defaults we want to use, and returns an +/// [`ItemImpl`] containing the final generated impl. +/// +/// This process has the following caveats: +/// * Colliding items that have an ident are not copied into `local_impl` +/// * Uncolliding items that have an ident are copied into `local_impl` but are qualified as `type +/// #ident = <#foreign_path as #source_crate_path::pallet::DefaultConfig>::#ident;` +/// * Items that lack an ident are de-duplicated so only unique items that lack an ident are copied +/// into `local_impl`. Items that lack an ident and also exist verbatim in `local_impl` are not +/// copied over. fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl, foreign_path: Path) -> ItemImpl { let existing_local_keys: HashSet = local_impl .items @@ -44,43 +56,40 @@ fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl, foreign_path: Pat .filter(|impl_item| impl_item_ident(impl_item).is_none()) .cloned() .collect(); - // // TODO: may not be accurate. - // // source_crate_path = frame_system let source_crate_path = foreign_path.segments.first().unwrap().ident.clone(); let mut final_impl = local_impl; - final_impl.items.extend( - foreign_impl - .items - .into_iter() - .filter_map(|item| { - if let Some(ident) = impl_item_ident(&item) { - if existing_local_keys.contains(&ident) { - // do not copy colliding items that have an ident - None - } else { - if matches!(item, ImplItem::Type(_)) { - // modify and insert uncolliding type items - let modified_item: ImplItem = parse_quote! { - type #ident = <#foreign_path as #source_crate_path::pallet::DefaultConfig>::#ident; - }; - Some(modified_item) - } else { - // copy uncolliding non-type items that have an ident - Some(item) - } - } + let extended_items = foreign_impl + .items + .into_iter() + .filter_map(|item| { + if let Some(ident) = impl_item_ident(&item) { + if existing_local_keys.contains(&ident) { + // do not copy colliding items that have an ident + None } else { - if existing_unsupported_items.contains(&item) { - // do not copy colliding items that lack an ident - None + if matches!(item, ImplItem::Type(_)) { + // modify and insert uncolliding type items + let modified_item: ImplItem = parse_quote! { + type #ident = <#foreign_path as #source_crate_path::pallet::DefaultConfig>::#ident; + }; + Some(modified_item) } else { - // copy uncolliding items without an ident verbaitm + // copy uncolliding non-type items that have an ident Some(item) } } - }) - .collect::>(), - ); + } else { + if existing_unsupported_items.contains(&item) { + // do not copy colliding items that lack an ident + None + } else { + // copy uncolliding items without an ident verbaitm + Some(item) + } + } + }) + .collect::>(); + final_impl.items.extend(extended_items); final_impl } From d72da33417329cf07fb991d5f33073f41f75d5a7 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 29 Mar 2023 12:42:03 -0400 Subject: [PATCH 020/116] add support for macros to impl_item_ident in case we hit that --- frame/support/procedural/src/derive_impl.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 33bf2e6c96362..07b40b344d6bf 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -28,6 +28,7 @@ fn impl_item_ident(impl_item: &ImplItem) -> Option { ImplItem::Const(item) => Some(item.ident.clone()), ImplItem::Method(item) => Some(item.sig.ident.clone()), ImplItem::Type(item) => Some(item.ident.clone()), + ImplItem::Macro(item) => item.mac.path.get_ident().cloned(), _ => None, } } From d27b824205fd10595764a493406e8dc3090770ff Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 29 Mar 2023 12:44:55 -0400 Subject: [PATCH 021/116] add docs for impl_item_ident method --- frame/support/procedural/src/derive_impl.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 07b40b344d6bf..9cb80486cc83e 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -23,6 +23,11 @@ use quote::{quote, ToTokens}; use std::collections::HashSet; use syn::{parse2, parse_quote, Ident, ImplItem, ItemImpl, Path, Result}; +/// Gets the [`Ident`] representation of the given [`ImplItem`], if one exists. Otherwise +/// returns [`None`]. +/// +/// Used by [`combine_impls`] to determine whether we can compare [`ImplItem`]s by [`Ident`] +/// or not. fn impl_item_ident(impl_item: &ImplItem) -> Option { match impl_item { ImplItem::Const(item) => Some(item.ident.clone()), From 3e4c923eebbb0e40b1402ff7956fe0e974c64f93 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 30 Mar 2023 04:02:43 -0400 Subject: [PATCH 022/116] fix no_std issues --- Cargo.lock | 42 +++++++++------------ frame/examples/basic/Cargo.toml | 2 +- frame/support/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/src/derive_impl.rs | 2 +- frame/support/src/lib.rs | 1 + frame/system/Cargo.toml | 2 +- 7 files changed, 24 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99085a5d15229..98785a3b34648 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1115,15 +1115,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279" -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "core-foundation" version = "0.9.3" @@ -3775,6 +3766,15 @@ version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +[[package]] +name = "libc-print" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06cea5d58bd9ba4717bbf5c6c5bb11bb6e9e76685b7fff34039b80f50ce86c11" +dependencies = [ + "libc", +] + [[package]] name = "libgit2-sys" version = "0.14.2+1.5.1" @@ -4478,9 +4478,9 @@ dependencies = [ [[package]] name = "macro_magic" -version = "0.2.6" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b745dd26139d33d0c29799b8983eda0673e5e30613f9b3a42743c146c4bd887a" +checksum = "91164c80f941dea9c77312dd44813a655f45a2ae0a7b5f87c72275aac2441f91" dependencies = [ "macro_magic_core", "macro_magic_macros", @@ -4490,12 +4490,12 @@ dependencies = [ [[package]] name = "macro_magic_core" -version = "0.2.6" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b432f14f3e7100d45a36576b2acaa7f246cac3a0d3221715d9f16355a154838a" +checksum = "7c37a39d8acc9049fdd2faeb20983d5dcae911b0f51634e31daeea49db7d9673" dependencies = [ - "convert_case", "derive-syn-parse", + "libc-print", "macro_magic_core_macros", "prettyplease", "proc-macro2", @@ -4505,9 +4505,9 @@ dependencies = [ [[package]] name = "macro_magic_core_macros" -version = "0.2.6" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809c2526d4dfc5b3f30a6b80b45a5fcf1f15cabe4fb1094bc9c1d8e1857c7f35" +checksum = "0c1d949db0089faf1a78086afb016151d41d070b9d2e399545b66d22dc2da08e" dependencies = [ "proc-macro2", "quote", @@ -4516,9 +4516,9 @@ dependencies = [ [[package]] name = "macro_magic_macros" -version = "0.2.6" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccabbd32376feddaaed042c928a93368f6e1a0274d339857c379e43339e3daee" +checksum = "1dfa542442b41c04f49b644906d4da05c8b84984ce354d637700fd6a5d34ac49" dependencies = [ "macro_magic_core", "quote", @@ -12104,12 +12104,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - [[package]] name = "unicode-width" version = "0.1.10" diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index 471dda86d8fdb..b75d97d051296 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -23,7 +23,7 @@ pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../ sp-io = { version = "7.0.0", default-features = false, path = "../../../primitives/io" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } -macro_magic = "0.2.6" +macro_magic = "0.2.10" [dev-dependencies] sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 73a855cbc0211..e6f5c78b576cd 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -28,7 +28,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } tt-call = "1.0.8" -macro_magic = "0.2.6" +macro_magic = "0.2.10" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 9e4bc7858dfcd..e47a4423f40d1 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -23,7 +23,7 @@ proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.98", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } -macro_magic = "0.2.6" +macro_magic = { version = "0.2.9", features = ["pretty_print"] } [features] default = ["std"] diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 9cb80486cc83e..96abb2b2dff03 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -17,7 +17,7 @@ //! Implementation of the `derive_impl` attribute macro. -use macro_magic::core::pretty_print; +use macro_magic::mm_core::pretty_print; use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens}; use std::collections::HashSet; diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index f8c31f0aeac38..a705d3dbdcd02 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -829,6 +829,7 @@ macro_rules! assert_error_encoded_size { pub use serde::{Deserialize, Serialize}; #[doc(hidden)] +#[cfg(not(no_std))] pub mod macro_magic { pub use ::macro_magic::*; } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 23c175efc292a..39f9d9ab30192 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -macro_magic = "0.2.6" +macro_magic = "0.2.10" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } From d178975256009eb801f6e816e2ac5a57104686e5 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 30 Mar 2023 04:06:24 -0400 Subject: [PATCH 023/116] re-export of macro_magic working in pallets :tada: --- Cargo.lock | 1 - frame/examples/basic/Cargo.toml | 1 - frame/support/procedural/src/lib.rs | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 98785a3b34648..ed9c85b017773 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6076,7 +6076,6 @@ dependencies = [ "frame-support", "frame-system", "log", - "macro_magic", "pallet-balances", "parity-scale-codec", "scale-info", diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index b75d97d051296..2f854011b0abd 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -23,7 +23,6 @@ pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../ sp-io = { version = "7.0.0", default-features = false, path = "../../../primitives/io" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } -macro_magic = "0.2.10" [dev-dependencies] sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 3accbb23dcf8d..074cbb4859985 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -778,7 +778,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { .into() } -#[import_tokens_attr] +#[import_tokens_attr(frame_support::macro_magic)] #[proc_macro_attribute] pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { derive_impl::derive_impl(__source_path.into(), attrs.into(), input.into()) From 046b0b8863fac4878c77c362399d866c0ff142f1 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 31 Mar 2023 02:25:08 -0400 Subject: [PATCH 024/116] clean up + fully resolve no_std issue with macro_magic with v0.2.11 --- Cargo.lock | 16 +++++++-------- frame/support/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- .../procedural/src/pallet/expand/config.rs | 20 ------------------- frame/system/Cargo.toml | 2 +- 5 files changed, 11 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed9c85b017773..f82129150107e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4478,9 +4478,9 @@ dependencies = [ [[package]] name = "macro_magic" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91164c80f941dea9c77312dd44813a655f45a2ae0a7b5f87c72275aac2441f91" +checksum = "a152a5cbb38162d41f199300909bb74b52988ed8f83b3873d176cf8b6bd90c34" dependencies = [ "macro_magic_core", "macro_magic_macros", @@ -4490,9 +4490,9 @@ dependencies = [ [[package]] name = "macro_magic_core" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c37a39d8acc9049fdd2faeb20983d5dcae911b0f51634e31daeea49db7d9673" +checksum = "8864fb44cfc15606b1737fadf2123b4da4c683cda58ebed2eba7c42aeb864ea3" dependencies = [ "derive-syn-parse", "libc-print", @@ -4505,9 +4505,9 @@ dependencies = [ [[package]] name = "macro_magic_core_macros" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1d949db0089faf1a78086afb016151d41d070b9d2e399545b66d22dc2da08e" +checksum = "1df0d9a54b70af4ce9d7578b2a894e12ab39339e57450ddc3b6945429d9c8061" dependencies = [ "proc-macro2", "quote", @@ -4516,9 +4516,9 @@ dependencies = [ [[package]] name = "macro_magic_macros" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dfa542442b41c04f49b644906d4da05c8b84984ce354d637700fd6a5d34ac49" +checksum = "b2a16c5ca8fc1ba975a404091e22ed3b2feaeb623427b5ec9bf68341c10e9df1" dependencies = [ "macro_magic_core", "quote", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index e6f5c78b576cd..3ee8c706f65d8 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -28,7 +28,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } tt-call = "1.0.8" -macro_magic = "0.2.10" +macro_magic = "0.2.11" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index e47a4423f40d1..3ebeb14f76e52 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -23,7 +23,7 @@ proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.98", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } -macro_magic = { version = "0.2.9", features = ["pretty_print"] } +macro_magic = { version = "0.2.11", features = ["pretty_print", "proc_support"] } [features] default = ["std"] diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index 6622bee8984bb..d7988dc2848eb 100644 --- a/frame/support/procedural/src/pallet/expand/config.rs +++ b/frame/support/procedural/src/pallet/expand/config.rs @@ -63,31 +63,11 @@ pub fn expand_config(def: &mut Def) -> TokenStream { Ok(krate) => krate, Err(err) => return err.to_compile_error(), }; - quote!( #[#support::macro_magic::export_tokens] pub trait DefaultConfig { #(#trait_items)* } - - #[macro_export] - #[doc(hidden)] - // TODO: naming probably needs to be unique - macro_rules! tt_config_items { - { - $caller:tt - frame_support = [{$($frame_support:ident)::*}] - } => { - $( $frame_support )*::tt_return! { - $caller - type_items = [{ #(#associated_type_names),* }] - fn_items = [{ }] - const_items = [{ }] - } - } - } - - pub use tt_config_items as tt_config_items; ) } else { Default::default() diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 39f9d9ab30192..5f4172d0268dd 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -macro_magic = "0.2.10" +macro_magic = "0.2.11" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } From e3566dde377c0cbaf03156d0ad855d83a60e0745 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 31 Mar 2023 02:29:07 -0400 Subject: [PATCH 025/116] remove trait item code for different trait item types since this is now handled directly by combine_impls --- .../support/procedural/src/pallet/expand/config.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index d7988dc2848eb..baa5ae74cdda9 100644 --- a/frame/support/procedural/src/pallet/expand/config.rs +++ b/frame/support/procedural/src/pallet/expand/config.rs @@ -45,19 +45,6 @@ pub fn expand_config(def: &mut Def) -> TokenStream { } if let Some(trait_items) = &config.default_sub_trait { - let associated_type_names = config_item - .items - .iter() - .filter_map( - |i| if let syn::TraitItem::Type(t) = i { Some(t.ident.clone()) } else { None }, - ) - .collect::>(); - - // we rarely use const and fns in config traits anyways... maybe not supporting them is good - // enough. - let _const_names = Vec::::default(); - let _fn_names = Vec::::default(); - // get reference to frame_support let support = match generate_crate_access_2018("frame-support") { Ok(krate) => krate, From bd68211414e67b1ec9ca594f193f244cd67d6882 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Mon, 3 Apr 2023 19:01:54 -0400 Subject: [PATCH 026/116] clean up --- frame/support/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index a705d3dbdcd02..ac624181e2f0e 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -830,9 +830,7 @@ pub use serde::{Deserialize, Serialize}; #[doc(hidden)] #[cfg(not(no_std))] -pub mod macro_magic { - pub use ::macro_magic::*; -} +pub use macro_magic; #[cfg(test)] pub mod tests { From dce288d41f437c3e9f7ba80f3ed0b8da06c186d0 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 4 Apr 2023 20:48:59 -0400 Subject: [PATCH 027/116] remove dev comments --- frame/examples/basic/src/tests.rs | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 4827eda5ad84a..2b15c4e7606c3 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -64,33 +64,6 @@ impl frame_system::Config for Test { type AccountData = pallet_balances::AccountData; } -// impl frame_system::Config for Test { -// type BaseCallFilter = frame_support::traits::Everything; -// type BlockWeights = (); -// type BlockLength = (); -// type DbWeight = (); -// type RuntimeOrigin = RuntimeOrigin; -// type Index = u64; -// type BlockNumber = u64; -// type Hash = H256; -// type RuntimeCall = RuntimeCall; -// type Hashing = BlakeTwo256; -// type AccountId = u64; -// type Lookup = IdentityLookup; -// type Header = Header; -// type RuntimeEvent = RuntimeEvent; -// type BlockHashCount = ConstU64<250>; -// type Version = (); -// type PalletInfo = PalletInfo; -// type AccountData = pallet_balances::AccountData; -// type OnNewAccount = (); -// type OnKilledAccount = (); -// type SystemWeightInfo = (); -// type SS58Prefix = (); -// type OnSetCode = frame_system::DefaultSetCode; -// type MaxConsumers = frame_support::traits::ConstU32<16>; -// } - impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); From e061bbb006b2e995fc1dbbc1563d8f12d01fdc84 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 5 Apr 2023 11:32:14 -0400 Subject: [PATCH 028/116] only generate default trait if #[pallet::default_trait] is attached --- frame/balances/src/lib.rs | 2 +- frame/examples/basic/src/lib.rs | 2 +- frame/nomination-pools/src/lib.rs | 2 +- .../procedural/src/pallet/parse/config.rs | 8 +++- .../procedural/src/pallet/parse/mod.rs | 45 ++++++++++++------- frame/system/src/lib.rs | 3 +- 6 files changed, 38 insertions(+), 24 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 6594c3967d070..82bfce706b3a0 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -210,7 +210,7 @@ pub mod pallet { pub type CreditOf = Credit<::AccountId, Pallet>; - #[pallet::config] + #[pallet::default_config] pub trait Config: frame_system::Config { /// The overarching event type. type RuntimeEvent: From> diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index 706a088fa97f6..16e17f1f9c95f 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -363,7 +363,7 @@ pub mod pallet { /// should be added to our implied traits list. /// /// `frame_system::Config` should always be included. - #[pallet::config] + #[pallet::default_config] pub trait Config: pallet_balances::Config + frame_system::Config { // Setting a constant config parameter from the runtime #[pallet::constant] diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 8d6dea9b5b7ad..896a17cc89af3 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1503,7 +1503,7 @@ pub mod pallet { #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); - #[pallet::config] + #[pallet::default_config] pub trait Config: frame_system::Config { /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index b42b06d6aaa6f..a5b0bfe878191 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -356,6 +356,7 @@ impl ConfigDef { attr_span: proc_macro2::Span, index: usize, item: &mut syn::Item, + enable_default: bool, ) -> syn::Result { let item = if let syn::Item::Trait(item) = item { item @@ -430,12 +431,15 @@ impl ConfigDef { // TODO: if we call this again, we should expect `Err(_)`. - if !no_default && !is_event { + if !no_default && !is_event && enable_default { default_subtrait_items.push(trait_item.clone()); } } - let default_sub_trait = Some(default_subtrait_items); + let default_sub_trait = match enable_default { + true => Some(default_subtrait_items), + false => None, + }; let attr: Option = helper::take_first_item_pallet_attr(&mut item.attrs)?; diff --git a/frame/support/procedural/src/pallet/parse/mod.rs b/frame/support/procedural/src/pallet/parse/mod.rs index 94e6f7a7c2f7d..94b848069bbe5 100644 --- a/frame/support/procedural/src/pallet/parse/mod.rs +++ b/frame/support/procedural/src/pallet/parse/mod.rs @@ -97,7 +97,11 @@ impl Def { match pallet_attr { Some(PalletAttr::Config(span)) if config.is_none() => - config = Some(config::ConfigDef::try_from(&frame_system, span, index, item)?), + config = + Some(config::ConfigDef::try_from(&frame_system, span, index, item, false)?), + Some(PalletAttr::DefaultConfig(span)) if config.is_none() => + config = + Some(config::ConfigDef::try_from(&frame_system, span, index, item, true)?), Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => { let p = pallet_struct::PalletStructDef::try_from(span, index, item)?; pallet_struct = Some(p); @@ -369,28 +373,32 @@ impl GenericKind { /// List of additional token to be used for parsing. mod keyword { - syn::custom_keyword!(origin); - syn::custom_keyword!(call); - syn::custom_keyword!(event); - syn::custom_keyword!(config); - syn::custom_keyword!(hooks); - syn::custom_keyword!(inherent); - syn::custom_keyword!(error); - syn::custom_keyword!(storage); - syn::custom_keyword!(genesis_build); - syn::custom_keyword!(genesis_config); - syn::custom_keyword!(validate_unsigned); - syn::custom_keyword!(type_value); - syn::custom_keyword!(pallet); - syn::custom_keyword!(generate_store); - syn::custom_keyword!(Store); - syn::custom_keyword!(extra_constants); + use syn::custom_keyword; + + custom_keyword!(origin); + custom_keyword!(call); + custom_keyword!(event); + custom_keyword!(config); + custom_keyword!(default_config); + custom_keyword!(hooks); + custom_keyword!(inherent); + custom_keyword!(error); + custom_keyword!(storage); + custom_keyword!(genesis_build); + custom_keyword!(genesis_config); + custom_keyword!(validate_unsigned); + custom_keyword!(type_value); + custom_keyword!(pallet); + custom_keyword!(generate_store); + custom_keyword!(Store); + custom_keyword!(extra_constants); } /// Parse attributes for item in pallet module /// syntax must be `pallet::` (e.g. `#[pallet::config]`) enum PalletAttr { Config(proc_macro2::Span), + DefaultConfig(proc_macro2::Span), Pallet(proc_macro2::Span), Hooks(proc_macro2::Span), RuntimeCall(proc_macro2::Span), @@ -410,6 +418,7 @@ impl PalletAttr { fn span(&self) -> proc_macro2::Span { match self { Self::Config(span) => *span, + Self::DefaultConfig(span) => *span, Self::Pallet(span) => *span, Self::Hooks(span) => *span, Self::RuntimeCall(span) => *span, @@ -438,6 +447,8 @@ impl syn::parse::Parse for PalletAttr { let lookahead = content.lookahead1(); if lookahead.peek(keyword::config) { Ok(PalletAttr::Config(content.parse::()?.span())) + } else if lookahead.peek(keyword::default_config) { + Ok(PalletAttr::DefaultConfig(content.parse::()?.span())) } else if lookahead.peek(keyword::pallet) { Ok(PalletAttr::Pallet(content.parse::()?.span())) } else if lookahead.peek(keyword::hooks) { diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 3f6d2274a0bcb..a37308eb7bf0a 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -235,8 +235,7 @@ pub mod pallet { } /// System configuration trait. Implemented by runtime. - #[pallet::config] - // TODO: #[pallet::default_config] + #[pallet::default_config] #[pallet::disable_frame_system_supertrait_check] pub trait Config: 'static + Eq + Clone { /// The aggregated event type of the runtime. From 8b8a11efcb55ae18db52f244535fa4d04e2f09a0 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 5 Apr 2023 20:57:59 -0400 Subject: [PATCH 029/116] authorship and most other pallets now compiling --- frame/system/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index a37308eb7bf0a..c067d46110d9c 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -153,13 +153,12 @@ pub type ConsumedWeight = PerDispatchClass; pub use pallet::*; /// Do something when we should be setting the code. -pub trait SetCode { +pub trait SetCode { /// Set the code to the given blob. fn set_code(code: Vec) -> DispatchResult; } -pub struct DefaultSetCode(sp_std::marker::PhantomData); -impl SetCode for DefaultSetCode { +impl SetCode for () { fn set_code(code: Vec) -> DispatchResult { >::update_code_in_storage(&code)?; Ok(()) @@ -391,7 +390,7 @@ pub mod pallet { /// It's unlikely that this needs to be customized, unless you are writing a parachain using /// `Cumulus`, where the actual code change is deferred. #[pallet::no_default] - type OnSetCode: SetCode; + type OnSetCode: SetCode; /// The maximum number of consumers allowed on a single account. type MaxConsumers: ConsumerLimits; From 271186a28dc7bb78c2bdd13da57d6c8bf225cf3d Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 5 Apr 2023 21:39:19 -0400 Subject: [PATCH 030/116] compiling :tada: --- frame/examples/basic/src/tests.rs | 2 +- frame/nomination-pools/src/lib.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 2b15c4e7606c3..4f539e42e6a97 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -57,7 +57,7 @@ impl frame_system::Config for Test { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type RuntimeOrigin = RuntimeOrigin; - type OnSetCode = frame_system::DefaultSetCode; + type OnSetCode = (); type PalletInfo = PalletInfo; type Header = Header; // We decide to override this one. diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 896a17cc89af3..f3c4bc33133f9 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1549,9 +1549,11 @@ pub mod pallet { type MaxPointsToBalance: Get; /// Infallible method for converting `Currency::Balance` to `U256`. + #[pallet::no_default] type BalanceToU256: Convert, U256>; /// Infallible method for converting `U256` to `Currency::Balance`. + #[pallet::no_default] type U256ToBalance: Convert>; /// The interface for nominating. From 48506f7617cb7011bf24e7abd9079428a5bf1316 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 6 Apr 2023 01:20:27 -0400 Subject: [PATCH 031/116] add check for more than two pallet attributes on Config trait --- .../procedural/src/pallet/parse/config.rs | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index a5b0bfe878191..59c9e1943fde0 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -17,8 +17,9 @@ use super::helper; use frame_support_procedural_tools::get_doc_literals; +use proc_macro2::Span; use quote::ToTokens; -use syn::spanned::Spanned; +use syn::{spanned::Spanned, Attribute, TraitItem}; /// List of additional token to be used for parsing. mod keyword { @@ -350,6 +351,42 @@ pub fn replace_self_by_t(input: proc_macro2::TokenStream) -> proc_macro2::TokenS .collect() } +/// Returns the number of non-trivial attributes attached to a [`syn::TraitItem`]. Returns `0` +/// for edge cases such as [`TraitItem::Verbatim`]. Also returns an appropriate span for the +/// first attribute, if applicable. This function ignores doc comments and `#[cfg(..)]` +/// directives. +fn get_num_pallet_trait_item_attrs_with_span(trait_item: &TraitItem) -> syn::Result<(usize, Span)> { + let attrs = match trait_item { + TraitItem::Const(trait_item_const) => &trait_item_const.attrs, + TraitItem::Method(trait_item_method) => &trait_item_method.attrs, + TraitItem::Type(trait_item_type) => &trait_item_type.attrs, + TraitItem::Macro(trait_item_macro) => &trait_item_macro.attrs, + _ => return Ok((0, trait_item.span())), + }; + let mut without_docs: Vec<&Attribute> = Vec::new(); + for attr in attrs { + if let Some(meta_ident) = attr.parse_meta()?.path().get_ident().cloned() { + if meta_ident == "doc" || meta_ident == "cfg" { + // ignore doc and cfg directives + continue + } + } + if let Some(seg) = attr.path.segments.first() { + if seg.ident != "pallet" { + // ignore attributes not starting with `#[pallet::` + continue + } + } + without_docs.push(attr); + } + let attrs = without_docs; + if let Some(attr) = attrs.first() { + Ok((attrs.len(), attr.span())) + } else { + Ok((0, trait_item.span())) + } +} + impl ConfigDef { pub fn try_from( frame_system: &syn::Ident, @@ -429,7 +466,15 @@ impl ConfigDef { process_attr()?; process_attr()?; - // TODO: if we call this again, we should expect `Err(_)`. + // ensure there are no more attrs on `trait_item` that haven't been consumed + let (num_remaining_attrs, attr_span) = + get_num_pallet_trait_item_attrs_with_span(trait_item)?; + if num_remaining_attrs > 0 { + return Err(syn::Error::new( + attr_span, + "Invalid attribute in pallet::config, a maximum of two attributes are expected", + )) + } if !no_default && !is_event && enable_default { default_subtrait_items.push(trait_item.clone()); From d5bda5f0960a940266cf575c352638e15824df52 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 6 Apr 2023 01:27:44 -0400 Subject: [PATCH 032/116] remove unused import in nomination-pool --- frame/nomination-pools/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index f3c4bc33133f9..b3362432e4b6f 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1494,7 +1494,6 @@ pub mod pallet { use frame_support::traits::StorageVersion; use frame_system::{ensure_signed, pallet_prelude::*}; use sp_runtime::Perbill; - use sp_core::parameter_types; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); From 7fc7665314c08704dc177e2b15065e58405ac411 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 6 Apr 2023 01:36:19 -0400 Subject: [PATCH 033/116] clean up debug code --- Cargo.lock | 11 ----------- frame/support/procedural/Cargo.toml | 2 +- frame/support/procedural/src/derive_impl.rs | 12 +----------- 3 files changed, 2 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f82129150107e..c44d0f7490974 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3766,15 +3766,6 @@ version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" -[[package]] -name = "libc-print" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06cea5d58bd9ba4717bbf5c6c5bb11bb6e9e76685b7fff34039b80f50ce86c11" -dependencies = [ - "libc", -] - [[package]] name = "libgit2-sys" version = "0.14.2+1.5.1" @@ -4495,9 +4486,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8864fb44cfc15606b1737fadf2123b4da4c683cda58ebed2eba7c42aeb864ea3" dependencies = [ "derive-syn-parse", - "libc-print", "macro_magic_core_macros", - "prettyplease", "proc-macro2", "quote", "syn", diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 3ebeb14f76e52..4b230e2f9e0f4 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -23,7 +23,7 @@ proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.98", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } -macro_magic = { version = "0.2.11", features = ["pretty_print", "proc_support"] } +macro_magic = { version = "0.2.11", features = ["proc_support"] } [features] default = ["std"] diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 96abb2b2dff03..fdae1e057a898 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -17,9 +17,8 @@ //! Implementation of the `derive_impl` attribute macro. -use macro_magic::mm_core::pretty_print; use proc_macro2::TokenStream as TokenStream2; -use quote::{quote, ToTokens}; +use quote::quote; use std::collections::HashSet; use syn::{parse2, parse_quote, Ident, ImplItem, ItemImpl, Path, Result}; @@ -104,20 +103,11 @@ pub fn derive_impl( foreign_tokens: TokenStream2, local_tokens: TokenStream2, ) -> Result { - println!("foreign_path: {}\n", foreign_path.to_string()); - println!("foreign_impl:"); - pretty_print(&foreign_tokens); - println!("\nlocal_impl:"); - pretty_print(&local_tokens); - let local_impl = parse2::(local_tokens)?; let foreign_impl = parse2::(foreign_tokens)?; let foreign_path = parse2::(foreign_path)?; let combined_impl = combine_impls(local_impl, foreign_impl, foreign_path); - println!("combined_impl:"); - pretty_print(&combined_impl.to_token_stream()); - Ok(quote!(#combined_impl)) } From 9e318580a9bbf4918dedf294569411f6d64cc84d Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 6 Apr 2023 17:43:22 -0400 Subject: [PATCH 034/116] upgrade to macro_magic v0.2.12 --- Cargo.lock | 16 ++++++++-------- frame/support/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 630890e0dd068..74d278bb09379 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4488,9 +4488,9 @@ dependencies = [ [[package]] name = "macro_magic" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152a5cbb38162d41f199300909bb74b52988ed8f83b3873d176cf8b6bd90c34" +checksum = "01f487951eb9288246a9126ad13ebc7c181075386cc6682edb13bd35322d5c61" dependencies = [ "macro_magic_core", "macro_magic_macros", @@ -4500,9 +4500,9 @@ dependencies = [ [[package]] name = "macro_magic_core" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8864fb44cfc15606b1737fadf2123b4da4c683cda58ebed2eba7c42aeb864ea3" +checksum = "b6cec7bf116c673ed7e08487a63610e5bf14efec93280f9b13ee931cdb296f14" dependencies = [ "derive-syn-parse", "macro_magic_core_macros", @@ -4513,9 +4513,9 @@ dependencies = [ [[package]] name = "macro_magic_core_macros" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df0d9a54b70af4ce9d7578b2a894e12ab39339e57450ddc3b6945429d9c8061" +checksum = "9621f21ce62f663011b5e11b3129c7de52defc8a532894d647aa5a4f47de4fdb" dependencies = [ "proc-macro2", "quote", @@ -4524,9 +4524,9 @@ dependencies = [ [[package]] name = "macro_magic_macros" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a16c5ca8fc1ba975a404091e22ed3b2feaeb623427b5ec9bf68341c10e9df1" +checksum = "be2b74b1bff1a3a095d0e746d42eaa71aadb72d4e552d649eb572d1141fa479d" dependencies = [ "macro_magic_core", "quote", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 3ee8c706f65d8..ea4a953ba8224 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -28,7 +28,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } tt-call = "1.0.8" -macro_magic = "0.2.11" +macro_magic = "0.2.12" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index b0caf58a9d051..ad98af694326b 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -23,7 +23,7 @@ proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.98", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } -macro_magic = { version = "0.2.11", features = ["proc_support"] } +macro_magic = { version = "0.2.12", features = ["proc_support"] } proc-macro-warning = { version = "0.2.0", default-features = false } [features] diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 5f4172d0268dd..96f5b7ce332ba 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -macro_magic = "0.2.11" +macro_magic = "0.2.12" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } From 5b8019b2159c1eaa151f0a234620d8572e41aa0f Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 7 Apr 2023 00:51:24 -0400 Subject: [PATCH 035/116] add neater #[register_default_config(SomeIdent)] macro * really just a thin wrapper around #[export_tokens] --- frame/support/procedural/src/lib.rs | 75 +++++++++++++++++++++++++++++ frame/support/src/lib.rs | 4 ++ frame/system/src/lib.rs | 3 +- 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 9bb1c7331ded0..e59fbf12f0735 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -786,6 +786,81 @@ pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { .into() } +/// Attach this attribute to an impl statement that implements the auto-generated +/// `DefaultConfig` trait for a default config that needs to be registered for use with the +/// [`derive_impl`] attribute macro. +/// +/// You must also specify an ident as the only argument to the attribute. This ident will be +/// used as the export name for this default config impl, and is the name you must provide to +/// [`derive_impl`] when you import this impl. +/// +/// The ident you provide is exported at the root of the crate where it is defined, so the +/// ident must be unique at the crate level so as not to collide with other items. This is +/// because internally this attribute aliases to macro_magic's `#[export_tokens]` macro, which +/// relies on crate-level `macro_rules!` exports to export tokens for use elsewhere. +/// +/// ## Example +/// +/// ```ignore +/// pub struct ExampleTestDefaultConfig {} +/// +/// #[register_default_config(ExampleTestDefaultConfig)] +/// impl DefaultConfig for ExampleTestDefaultConfig { +/// type Version = (); +/// type BlockWeights = (); +/// type BlockLength = (); +/// ... +/// type SS58Prefix = (); +/// type MaxConsumers = frame_support::traits::ConstU32<16>; +/// } +/// ``` +/// +/// This macro acts as a thin wrapper around macro_magic's `#[export_tokens]`. See the docs +/// [here](https://docs.rs/macro_magic/latest/macro_magic/attr.export_tokens.html) for more info. +#[proc_macro_attribute] +pub fn register_default_config(attrs: TokenStream, tokens: TokenStream) -> TokenStream { + // ensure this is an impl DefaultConfig for X impl + use syn::{ + parse::{Parse, ParseStream}, + token::Brace, + Attribute, Path, Token, TraitItem, + }; + syn::custom_keyword!(DefaultConfig); + struct TraitContents { + _contents: Vec, + } + impl Parse for TraitContents { + fn parse(input: ParseStream) -> syn::Result { + let mut items = Vec::new(); + while !input.is_empty() { + items.push(input.parse()?); + } + Ok(TraitContents { _contents: items }) + } + } + #[derive(derive_syn_parse::Parse)] + struct DefaultConfigTraitImpl { + #[call(Attribute::parse_outer)] + _attrs: Vec, + _impl: Token![impl], + _default_config: DefaultConfig, + _for: Token![for], + _path: Path, + #[brace] + _brace: Brace, + #[inside(_brace)] + _contents: TraitContents, + } + let trait_tokens = tokens.clone(); + syn::parse_macro_input!(trait_tokens as DefaultConfigTraitImpl); + + // internally wrap macro_magic's `#[export_tokens]` macro + match macro_magic::mm_core::export_tokens_internal(attrs, tokens) { + Ok(tokens) => tokens.into(), + Err(err) => err.to_compile_error().into(), + } +} + /// Used internally to decorate pallet attribute macro stubs when they are erroneously used /// outside of a pallet module fn pallet_macro_stub() -> TokenStream { diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 7ae098058938f..3792347f4ec7a 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1485,6 +1485,7 @@ pub mod pallet_prelude { }; pub use codec::{Decode, Encode, MaxEncodedLen}; pub use frame_support::pallet_macros::*; + pub use frame_support_procedural::register_default_config; pub use scale_info::TypeInfo; pub use sp_runtime::{ traits::{MaybeSerializeDeserialize, Member, ValidateUnsigned}, @@ -2846,5 +2847,8 @@ pub mod pallet_macros { }; } +#[doc(inline)] +pub use frame_support_procedural::register_default_config; + // Generate a macro that will enable/disable code based on `std` feature being active. sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $); diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index c067d46110d9c..3085b8d92d576 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -205,12 +205,11 @@ pub mod pallet { pub mod testing { type AccountId = u64; use super::*; - use macro_magic::export_tokens; use sp_runtime::traits::IdentityLookup; pub struct TestDefaultConfig {} - #[export_tokens(TestDefaultConfig)] + #[register_default_config(TestDefaultConfig)] impl DefaultConfig for TestDefaultConfig { type Version = (); type BlockWeights = (); From ef9d10703085d43fc85c3a7c2568dd115d591d10 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 18 Apr 2023 17:49:13 -0400 Subject: [PATCH 036/116] upgrade to macro_magic 0.3.1 --- Cargo.lock | 24 ++++++++++++------------ frame/support/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 577e69a82e20b..ea8ad15a0bfee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4489,49 +4489,49 @@ dependencies = [ [[package]] name = "macro_magic" -version = "0.2.12" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01f487951eb9288246a9126ad13ebc7c181075386cc6682edb13bd35322d5c61" +checksum = "25fc0b6681924e4b8879bb0d6b1ca1e1dc899ca9b9b94044ad9f2b83f3fc7cbd" dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "macro_magic_core" -version = "0.2.12" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6cec7bf116c673ed7e08487a63610e5bf14efec93280f9b13ee931cdb296f14" +checksum = "22827765558bdea060552589146cae0d48bd65f6fa9a9b1a1171e97d6d2154fc" dependencies = [ "derive-syn-parse", "macro_magic_core_macros", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "macro_magic_core_macros" -version = "0.2.12" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9621f21ce62f663011b5e11b3129c7de52defc8a532894d647aa5a4f47de4fdb" +checksum = "871c8044d7dc35f3ac2971f5ee1f24274a4e5050a51a1ebeb746c061156fe32f" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "macro_magic_macros" -version = "0.2.12" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2b74b1bff1a3a095d0e746d42eaa71aadb72d4e552d649eb572d1141fa479d" +checksum = "a528638a982a6e41df0d198d7d8be56fb28e17d2b1e702472921871591e9ca55" dependencies = [ "macro_magic_core", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 3b9e81279967f..cfbacc52ffb78 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -28,7 +28,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } tt-call = "1.0.8" -macro_magic = "0.2.12" +macro_magic = "0.3.1" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index d6504d09388d1..0d4b0349c7f9a 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -24,7 +24,7 @@ quote = "1.0.26" syn = { version = "2.0.14", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } proc-macro-warning = { version = "0.3.0", default-features = false } -macro_magic = { version = "0.2.12", features = ["proc_support"] } +macro_magic = { version = "0.3.1", features = ["proc_support"] } [features] default = ["std"] diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 87189f0928e55..a0a3262abdac1 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -macro_magic = "0.2.12" +macro_magic = "0.3.1" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } From bc3237cf8a77d44f5086bd2acb546f8b05f62086 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 19 Apr 2023 03:15:04 -0400 Subject: [PATCH 037/116] rewrite parsing to be compatible with syn 2.x, compiling :tada: --- frame/support/procedural/src/derive_impl.rs | 2 +- frame/support/procedural/src/lib.rs | 2 +- .../procedural/src/pallet/parse/config.rs | 201 ++++-------------- 3 files changed, 43 insertions(+), 162 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index fdae1e057a898..16b5f13224863 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -30,7 +30,7 @@ use syn::{parse2, parse_quote, Ident, ImplItem, ItemImpl, Path, Result}; fn impl_item_ident(impl_item: &ImplItem) -> Option { match impl_item { ImplItem::Const(item) => Some(item.ident.clone()), - ImplItem::Method(item) => Some(item.sig.ident.clone()), + ImplItem::Fn(item) => Some(item.sig.ident.clone()), ImplItem::Type(item) => Some(item.ident.clone()), ImplItem::Macro(item) => item.mac.path.get_ident().cloned(), _ => None, diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index e59fbf12f0735..7662937db03c9 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -855,7 +855,7 @@ pub fn register_default_config(attrs: TokenStream, tokens: TokenStream) -> Token syn::parse_macro_input!(trait_tokens as DefaultConfigTraitImpl); // internally wrap macro_magic's `#[export_tokens]` macro - match macro_magic::mm_core::export_tokens_internal(attrs, tokens) { + match macro_magic::mm_core::export_tokens_internal(attrs, tokens, true) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), } diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index f6ac4b8c91751..ebd3f97766612 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -17,9 +17,8 @@ use super::helper; use frame_support_procedural_tools::get_doc_literals; -use proc_macro2::Span; use quote::ToTokens; -use syn::{spanned::Spanned, Attribute, TraitItem}; +use syn::{spanned::Spanned, token, Ident, Token}; /// List of additional token to be used for parsing. mod keyword { @@ -28,6 +27,7 @@ mod keyword { syn::custom_keyword!(T); syn::custom_keyword!(I); syn::custom_keyword!(config); + syn::custom_keyword!(pallet); syn::custom_keyword!(IsType); syn::custom_keyword!(RuntimeEvent); syn::custom_keyword!(Event); @@ -130,95 +130,20 @@ impl syn::parse::Parse for DisableFrameSystemSupertraitCheck { } } -/// Parse for `#[pallet::constant]` -pub struct TypeAttrConst { - pound_token: syn::Token![#], - bracket_token: syn::token::Bracket, - pallet_ident: syn::Ident, - path_sep_token: syn::token::PathSep, - constant_keyword: keyword::constant, +/// Parsing for `#[pallet::X]` +#[derive(derive_syn_parse::Parse)] +pub struct PalletAttr { + _pound: Token![#], + #[bracket] + _bracket: token::Bracket, + #[inside(_bracket)] + _pallet: keyword::pallet, + #[inside(_bracket)] + _sep: Token![::], + #[inside(_bracket)] + ident: Ident, } -impl syn::parse::Parse for TypeAttrConst { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let pound_token = input.parse::()?; - let content; - let bracket_token = syn::bracketed!(content in input); - let pallet_ident = content.parse::()?; - let path_sep_token = content.parse::()?; - let constant_keyword = content.parse::()?; - - Ok(Self { pound_token, bracket_token, pallet_ident, path_sep_token, constant_keyword }) - } -} - -impl ToTokens for TypeAttrConst { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - self.pound_token.to_tokens(tokens); - self.bracket_token.surround(tokens, |tokens| { - self.pallet_ident.to_tokens(tokens); - self.path_sep_token.to_tokens(tokens); - self.constant_keyword.to_tokens(tokens); - }) - } -} - -/// Parse for `#[pallet::no_default]`. -pub struct TypeAttrNoDefault(proc_macro2::Span); - -impl Spanned for TypeAttrNoDefault { - fn span(&self) -> proc_macro2::Span { - self.0 - } -} - -impl syn::parse::Parse for TypeAttrNoDefault { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - input.parse::()?; - let content; - syn::bracketed!(content in input); - content.parse::()?; - content.parse::()?; - - Ok(TypeAttrNoDefault(content.parse::()?.span())) - } -} - -pub enum TypeAttrNoDefaultOrConst { - NoDefault(TypeAttrNoDefault), - Const(TypeAttrConst), -} - -impl Spanned for TypeAttrNoDefaultOrConst { - fn span(&self) -> proc_macro2::Span { - match self { - Self::Const(i) => i.0, - Self::NoDefault(i) => i.0, - } - } -} - -impl syn::parse::Parse for TypeAttrNoDefaultOrConst { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - input.parse::()?; - let content; - syn::bracketed!(content in input); - content.parse::()?; - content.parse::()?; - - Ok(if content.peek(keyword::no_default) { - TypeAttrNoDefaultOrConst::NoDefault(TypeAttrNoDefault( - content.parse::()?.span(), - )) - } else { - TypeAttrNoDefaultOrConst::Const(TypeAttrConst( - content.parse::()?.span(), - )) - }) - } -} - -/// Parse for `$ident::Config` pub struct ConfigBoundParse(syn::Ident); impl syn::parse::Parse for ConfigBoundParse { @@ -363,42 +288,6 @@ pub fn replace_self_by_t(input: proc_macro2::TokenStream) -> proc_macro2::TokenS .collect() } -/// Returns the number of non-trivial attributes attached to a [`syn::TraitItem`]. Returns `0` -/// for edge cases such as [`TraitItem::Verbatim`]. Also returns an appropriate span for the -/// first attribute, if applicable. This function ignores doc comments and `#[cfg(..)]` -/// directives. -fn get_num_pallet_trait_item_attrs_with_span(trait_item: &TraitItem) -> syn::Result<(usize, Span)> { - let attrs = match trait_item { - TraitItem::Const(trait_item_const) => &trait_item_const.attrs, - TraitItem::Method(trait_item_method) => &trait_item_method.attrs, - TraitItem::Type(trait_item_type) => &trait_item_type.attrs, - TraitItem::Macro(trait_item_macro) => &trait_item_macro.attrs, - _ => return Ok((0, trait_item.span())), - }; - let mut without_docs: Vec<&Attribute> = Vec::new(); - for attr in attrs { - if let Some(meta_ident) = attr.parse_meta()?.path().get_ident().cloned() { - if meta_ident == "doc" || meta_ident == "cfg" { - // ignore doc and cfg directives - continue - } - } - if let Some(seg) = attr.path.segments.first() { - if seg.ident != "pallet" { - // ignore attributes not starting with `#[pallet::` - continue - } - } - without_docs.push(attr); - } - let attrs = without_docs; - if let Some(attr) = attrs.first() { - Ok((attrs.len(), attr.span())) - } else { - Ok((0, trait_item.span())) - } -} - impl ConfigDef { pub fn try_from( frame_system: &syn::Ident, @@ -450,42 +339,34 @@ impl ConfigDef { let mut no_default = false; has_event_type = has_event_type || is_event; - // TODO: lots of extra checking that needs to be done.. this is just POC - let mut process_attr = || { - let no_default_or_const: Option = - helper::take_first_item_pallet_attr(trait_item)?; - match no_default_or_const { - Some(TypeAttrNoDefaultOrConst::Const(_)) => match trait_item { - syn::TraitItem::Type(ref type_) => { - let constant = ConstMetadataDef::try_from(type_)?; - consts_metadata.push(constant); - }, - _ => { - let msg = - "Invalid pallet::constant in pallet::config, expected type trait item"; - return Err(syn::Error::new(trait_item.span(), msg)) - }, - }, - Some(TypeAttrNoDefaultOrConst::NoDefault(_)) => { - no_default = true; - }, - None => {}, + for _ in 0..2 { + if let Ok(Some(pallet_attr)) = + helper::take_first_item_pallet_attr::(trait_item) + { + if pallet_attr.ident == "constant" { + match trait_item { + syn::TraitItem::Type(ref typ) => { + let constant = ConstMetadataDef::try_from(typ)?; + consts_metadata.push(constant); + }, + _ => { + let msg = + "Invalid pallet::constant in pallet::config, expected type trait item"; + return Err(syn::Error::new(trait_item.span(), msg)) + }, + } + } else if pallet_attr.ident == "no_default" { + no_default = true + } else { + return Err(syn::Error::new( + pallet_attr.ident.span(), + format!( + "Unsupported attribute `#[pallet::{}]` attached to a pallet config item", + pallet_attr.ident.to_string() + ), + )) + } } - Ok(()) - }; - - // process at most twice. - process_attr()?; - process_attr()?; - - // ensure there are no more attrs on `trait_item` that haven't been consumed - let (num_remaining_attrs, attr_span) = - get_num_pallet_trait_item_attrs_with_span(trait_item)?; - if num_remaining_attrs > 0 { - return Err(syn::Error::new( - attr_span, - "Invalid attribute in pallet::config, a maximum of two attributes are expected", - )) } if !no_default && !is_event && enable_default { From d17c807f16baf9b15a007ca1dc3e562204343777 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 19 Apr 2023 09:24:23 -0400 Subject: [PATCH 038/116] remove unused keywords --- frame/support/procedural/src/pallet/parse/config.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index ebd3f97766612..8e0ac3de050bd 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -31,8 +31,6 @@ mod keyword { syn::custom_keyword!(IsType); syn::custom_keyword!(RuntimeEvent); syn::custom_keyword!(Event); - syn::custom_keyword!(constant); - syn::custom_keyword!(no_default); syn::custom_keyword!(frame_system); syn::custom_keyword!(disable_frame_system_supertrait_check); } From 4d089e5786f88d6e3b4f84c7ee1d6df1aa39d8ce Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Sat, 22 Apr 2023 01:05:42 -0400 Subject: [PATCH 039/116] macro stubs for the new pallet:: macros, preliminary docs --- frame/support/procedural/src/derive_impl.rs | 8 ++ frame/support/procedural/src/lib.rs | 127 +++++++++++++++++++- frame/support/src/lib.rs | 4 +- 3 files changed, 135 insertions(+), 4 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 16b5f13224863..c234988d5650d 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -98,6 +98,14 @@ fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl, foreign_path: Pat final_impl } +/// Internal implementation behind [`#[derive_impl(..)]`](`macro@crate::derive_impl`). +/// +/// `foreign_path`: the module path of the external `impl` statement whose tokens we are +/// importing via `macro_magic` +/// +/// `foreign_tokens`: the tokens for the external `impl` statement +/// +/// `local_tokens`: the tokens for the local `impl` statement this attribute is attached to pub fn derive_impl( foreign_path: TokenStream2, foreign_tokens: TokenStream2, diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 7662937db03c9..2486bce4cb5bc 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -778,6 +778,102 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { .into() } +/// This attribtue can be used to derive a test pallet `Config` based on an existing pallet +/// `Config` that has been marked with [`#[pallet::default_config]`](`macro@default_config`). +/// +/// The attribute should be attached to an `impl` block that implements a compatible `Config` +/// such as `frame_system::Config` for a test/mock runtime, and should receive as its only +/// argument the path to a `DefaultConfig` impl that has been registered via +/// [`#[register_default_config]`](`macro@register_default_config`). +/// +/// Consider the following taken from the basic example pallet: +/// +/// ```ignore +/// #[derive_impl(TestDefaultConfig)] +/// impl frame_system::Config for Test { +/// // These are all defined by system as mandatory. +/// type BaseCallFilter = frame_support::traits::Everything; +/// type RuntimeEvent = RuntimeEvent; +/// type RuntimeCall = RuntimeCall; +/// type RuntimeOrigin = RuntimeOrigin; +/// type OnSetCode = (); +/// type PalletInfo = PalletInfo; +/// type Header = Header; +/// // We decide to override this one. +/// type AccountData = pallet_balances::AccountData; +/// } +/// ``` +/// +/// where `TestDefaultConfig` was defined and registered as +/// follows: +/// +/// ```ignore +/// pub struct TestDefaultConfig {} +/// +/// #[register_default_config(TestDefaultConfig)] +/// impl DefaultConfig for TestDefaultConfig { +/// type Version = (); +/// type BlockWeights = (); +/// type BlockLength = (); +/// type DbWeight = (); +/// type Index = u64; +/// type BlockNumber = u64; +/// type Hash = sp_core::hash::H256; +/// type Hashing = sp_runtime::traits::BlakeTwo256; +/// type AccountId = AccountId; +/// type Lookup = IdentityLookup; +/// type BlockHashCount = frame_support::traits::ConstU64<10>; +/// type AccountData = u32; +/// type OnNewAccount = (); +/// type OnKilledAccount = (); +/// type SystemWeightInfo = (); +/// type SS58Prefix = (); +/// type MaxConsumers = frame_support::traits::ConstU32<16>; +/// } +/// ``` +/// +/// The above call to `derive_impl` would expand to roughly the following: +/// +/// ```ignore +/// impl frame_system::Config for Test { +/// use frame_system::preludes::testing::TestDefaultConfig; +/// use frame_system::pallet::DefaultConfig; +/// +/// type BaseCallFilter = frame_support::traits::Everything; +/// type RuntimeEvent = RuntimeEvent; +/// type RuntimeCall = RuntimeCall; +/// type RuntimeOrigin = RuntimeOrigin; +/// type OnSetCode = (); +/// type PalletInfo = PalletInfo; +/// type Header = Header; +/// type AccountData = pallet_balances::AccountData; +/// type Version = ::Version; +/// type BlockWeights = ::BlockWeights; +/// type BlockLength = ::BlockLength; +/// type DbWeight = ::DbWeight; +/// type Index = ::Index; +/// type BlockNumber = ::BlockNumber; +/// type Hash = ::Hash; +/// type Hashing = ::Hashing; +/// type AccountId = ::AccountId; +/// type Lookup = ::Lookup; +/// type BlockHashCount = ::BlockHashCount; +/// type OnNewAccount = ::OnNewAccount; +/// type OnKilledAccount = ::OnKilledAccount; +/// type SystemWeightInfo = ::SystemWeightInfo; +/// type SS58Prefix = ::SS58Prefix; +/// type MaxConsumers = ::MaxConsumers; +/// } +/// ``` +/// +/// You can then use the resulting `Test` config in test scenarios. +/// +/// Note that items that are _not_ present in our local +/// [`#[pallet::default_config]`](`macro@default_config`) are automatically copied from the +/// foreign trait (in this case `TestDefaultConfig`) into the local trait impl (in this case +/// `Test`), unless the trait item in the local trait impl is marked with +/// [`#[pallet::no_default]`], in which case it cannot be overridden, and any attempts to do so +/// will result in a compiler error. #[import_tokens_attr(frame_support::macro_magic)] #[proc_macro_attribute] pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { @@ -786,13 +882,40 @@ pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { .into() } +/// The optional attribute `#[pallet::default_config]` can be attached to a `Config` trait +/// within your pallet to mark it as auto-derivable under test conditions via +/// [`[#[derive_impl(..)]`](`macro@derive_impl`). +/// +/// You may use [`#[pallet::no_default]`](`macro@no_default`) and +/// [`#[pallet::constant]`](`macro@constant`) on individual trait items within your `Config` +/// trait. +/// +/// The [`#[pallet::no_default]`](`macro@no_default`) attribute allows you to specify that a +/// particular trait item _cannot_ be used as a default when a test `Config` is derived using +/// the [`#[derive_impl(..)]`](`macro@derive_impl`) attribute macro. +#[proc_macro_attribute] +pub fn default_config(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The optional attribute `#[pallet::no_default]` can be attached to trait items within a +/// `Config` trait impl that has [`#[pallet::default_config]`](`macro@default_config`) attached +/// to it. +/// +/// Attaching this attribute to a trait item ensures that that trait item will not be used as a +/// default with the [`#[derive_impl(..)]`](`macro@derive_impl`) attribute macro. +#[proc_macro_attribute] +pub fn no_default(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// Attach this attribute to an impl statement that implements the auto-generated /// `DefaultConfig` trait for a default config that needs to be registered for use with the -/// [`derive_impl`] attribute macro. +/// [`macro@derive_impl`] attribute macro. /// /// You must also specify an ident as the only argument to the attribute. This ident will be /// used as the export name for this default config impl, and is the name you must provide to -/// [`derive_impl`] when you import this impl. +/// [`macro@derive_impl`] when you import this impl. /// /// The ident you provide is exported at the root of the crate where it is defined, so the /// ident must be unique at the crate level so as not to collide with other items. This is diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index dfccc7b0f9f42..06db31ede2cbc 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -2842,8 +2842,8 @@ pub mod pallet_macros { call_index, compact, composite_enum, config, constant, disable_frame_system_supertrait_check, error, event, extra_constants, generate_deposit, generate_storage_info, generate_store, genesis_build, genesis_config, getter, hooks, - inherent, origin, storage, storage_prefix, storage_version, type_value, unbounded, - validate_unsigned, weight, whitelist_storage, + inherent, no_default, origin, storage, storage_prefix, storage_version, type_value, + unbounded, validate_unsigned, weight, whitelist_storage, }; } From 879de64041aa27ba01fc4b9dc3f131ac619ce59d Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Sat, 22 Apr 2023 01:20:03 -0400 Subject: [PATCH 040/116] upgrade to macro_magic v0.3.2 --- Cargo.lock | 16 ++++++++-------- frame/support/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea8ad15a0bfee..8adad1a39ccbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4489,9 +4489,9 @@ dependencies = [ [[package]] name = "macro_magic" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25fc0b6681924e4b8879bb0d6b1ca1e1dc899ca9b9b94044ad9f2b83f3fc7cbd" +checksum = "b5d5a7052e6c03bd1c402e6c43397d7720af36dbbae00249463fed6577a4a23c" dependencies = [ "macro_magic_core", "macro_magic_macros", @@ -4501,9 +4501,9 @@ dependencies = [ [[package]] name = "macro_magic_core" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22827765558bdea060552589146cae0d48bd65f6fa9a9b1a1171e97d6d2154fc" +checksum = "e1b4d334455d75e2cc97b238ae0f9de31ba3283060526d7634bc05b0e08c72e1" dependencies = [ "derive-syn-parse", "macro_magic_core_macros", @@ -4514,9 +4514,9 @@ dependencies = [ [[package]] name = "macro_magic_core_macros" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871c8044d7dc35f3ac2971f5ee1f24274a4e5050a51a1ebeb746c061156fe32f" +checksum = "959f99f3a496c4aaa574a9fa17be9a5aabbea3c2a4b0f7b9f55bb1cfe8d79b61" dependencies = [ "proc-macro2", "quote", @@ -4525,9 +4525,9 @@ dependencies = [ [[package]] name = "macro_magic_macros" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a528638a982a6e41df0d198d7d8be56fb28e17d2b1e702472921871591e9ca55" +checksum = "c24b7896b7c8378ff682bd6c344554b3f629ffefb423ce2a80eba5104a163cba" dependencies = [ "macro_magic_core", "quote", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index cfbacc52ffb78..820eda652c45f 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -28,7 +28,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } tt-call = "1.0.8" -macro_magic = "0.3.1" +macro_magic = "0.3.2" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 0d4b0349c7f9a..ef9449d3f046a 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -24,7 +24,7 @@ quote = "1.0.26" syn = { version = "2.0.14", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } proc-macro-warning = { version = "0.3.0", default-features = false } -macro_magic = { version = "0.3.1", features = ["proc_support"] } +macro_magic = { version = "0.3.2", features = ["proc_support"] } [features] default = ["std"] diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index a0a3262abdac1..812bf4542db6d 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -macro_magic = "0.3.1" +macro_magic = "0.3.2" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } From d697ee18c4d2ae89b9cd4eb9adb797ebbfebe44c Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Mon, 24 Apr 2023 23:10:06 -0400 Subject: [PATCH 041/116] rename register_default_config => register_default_impl --- frame/support/procedural/src/lib.rs | 50 ++++++----------------------- frame/support/src/lib.rs | 4 +-- frame/system/src/lib.rs | 2 +- 3 files changed, 12 insertions(+), 44 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 2486bce4cb5bc..a69c824cf311b 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -42,6 +42,7 @@ use proc_macro::TokenStream; use quote::{quote, ToTokens}; use std::{cell::RefCell, str::FromStr}; pub(crate) use storage::INHERENT_INSTANCE_NAME; +use syn::ItemImpl; thread_local! { /// A global counter, can be used to generate a relatively unique identifier. @@ -784,7 +785,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// The attribute should be attached to an `impl` block that implements a compatible `Config` /// such as `frame_system::Config` for a test/mock runtime, and should receive as its only /// argument the path to a `DefaultConfig` impl that has been registered via -/// [`#[register_default_config]`](`macro@register_default_config`). +/// [`#[register_default_impl]`](`macro@register_default_impl`). /// /// Consider the following taken from the basic example pallet: /// @@ -810,7 +811,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// ```ignore /// pub struct TestDefaultConfig {} /// -/// #[register_default_config(TestDefaultConfig)] +/// #[register_default_impl(TestDefaultConfig)] /// impl DefaultConfig for TestDefaultConfig { /// type Version = (); /// type BlockWeights = (); @@ -909,8 +910,7 @@ pub fn no_default(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// Attach this attribute to an impl statement that implements the auto-generated -/// `DefaultConfig` trait for a default config that needs to be registered for use with the +/// Attach this attribute to an impl statement that needs to be registered for use with the /// [`macro@derive_impl`] attribute macro. /// /// You must also specify an ident as the only argument to the attribute. This ident will be @@ -927,7 +927,7 @@ pub fn no_default(_: TokenStream, _: TokenStream) -> TokenStream { /// ```ignore /// pub struct ExampleTestDefaultConfig {} /// -/// #[register_default_config(ExampleTestDefaultConfig)] +/// #[register_default_impl(ExampleTestDefaultConfig)] /// impl DefaultConfig for ExampleTestDefaultConfig { /// type Version = (); /// type BlockWeights = (); @@ -941,44 +941,12 @@ pub fn no_default(_: TokenStream, _: TokenStream) -> TokenStream { /// This macro acts as a thin wrapper around macro_magic's `#[export_tokens]`. See the docs /// [here](https://docs.rs/macro_magic/latest/macro_magic/attr.export_tokens.html) for more info. #[proc_macro_attribute] -pub fn register_default_config(attrs: TokenStream, tokens: TokenStream) -> TokenStream { - // ensure this is an impl DefaultConfig for X impl - use syn::{ - parse::{Parse, ParseStream}, - token::Brace, - Attribute, Path, Token, TraitItem, - }; - syn::custom_keyword!(DefaultConfig); - struct TraitContents { - _contents: Vec, - } - impl Parse for TraitContents { - fn parse(input: ParseStream) -> syn::Result { - let mut items = Vec::new(); - while !input.is_empty() { - items.push(input.parse()?); - } - Ok(TraitContents { _contents: items }) - } - } - #[derive(derive_syn_parse::Parse)] - struct DefaultConfigTraitImpl { - #[call(Attribute::parse_outer)] - _attrs: Vec, - _impl: Token![impl], - _default_config: DefaultConfig, - _for: Token![for], - _path: Path, - #[brace] - _brace: Brace, - #[inside(_brace)] - _contents: TraitContents, - } - let trait_tokens = tokens.clone(); - syn::parse_macro_input!(trait_tokens as DefaultConfigTraitImpl); +pub fn register_default_impl(attrs: TokenStream, tokens: TokenStream) -> TokenStream { + // ensure this is a impl statement + let item_impl = syn::parse_macro_input!(tokens as ItemImpl); // internally wrap macro_magic's `#[export_tokens]` macro - match macro_magic::mm_core::export_tokens_internal(attrs, tokens, true) { + match macro_magic::mm_core::export_tokens_internal(attrs, item_impl.to_token_stream(), true) { Ok(tokens) => tokens.into(), Err(err) => err.to_compile_error().into(), } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 06db31ede2cbc..3d430d16fedda 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1485,7 +1485,7 @@ pub mod pallet_prelude { }; pub use codec::{Decode, Encode, MaxEncodedLen}; pub use frame_support::pallet_macros::*; - pub use frame_support_procedural::register_default_config; + pub use frame_support_procedural::register_default_impl; pub use scale_info::TypeInfo; pub use sp_runtime::{ traits::{MaybeSerializeDeserialize, Member, ValidateUnsigned}, @@ -2848,7 +2848,7 @@ pub mod pallet_macros { } #[doc(inline)] -pub use frame_support_procedural::register_default_config; +pub use frame_support_procedural::register_default_impl; // Generate a macro that will enable/disable code based on `std` feature being active. sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $); diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 3085b8d92d576..1ec1e6aa9b629 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -209,7 +209,7 @@ pub mod pallet { pub struct TestDefaultConfig {} - #[register_default_config(TestDefaultConfig)] + #[register_default_impl(TestDefaultConfig)] impl DefaultConfig for TestDefaultConfig { type Version = (); type BlockWeights = (); From f6c232e7ce4876dc230dbfc3df96f77023ee4ed0 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 26 Apr 2023 00:25:52 -0400 Subject: [PATCH 042/116] bump to macro_magic v0.3.3 --- Cargo.lock | 16 ++++++++-------- frame/support/Cargo.toml | 2 +- frame/support/procedural/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8adad1a39ccbf..328e00f7d23e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4489,9 +4489,9 @@ dependencies = [ [[package]] name = "macro_magic" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5d5a7052e6c03bd1c402e6c43397d7720af36dbbae00249463fed6577a4a23c" +checksum = "686f3703e9d296140171bbd6a6fa560e6059a35299ee3ce8c5bd646afa0c3992" dependencies = [ "macro_magic_core", "macro_magic_macros", @@ -4501,9 +4501,9 @@ dependencies = [ [[package]] name = "macro_magic_core" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b4d334455d75e2cc97b238ae0f9de31ba3283060526d7634bc05b0e08c72e1" +checksum = "e060da9399c1535b3f190084d7c6121bb3355b70c610110cff3f4978526f54e2" dependencies = [ "derive-syn-parse", "macro_magic_core_macros", @@ -4514,9 +4514,9 @@ dependencies = [ [[package]] name = "macro_magic_core_macros" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "959f99f3a496c4aaa574a9fa17be9a5aabbea3c2a4b0f7b9f55bb1cfe8d79b61" +checksum = "2fb9865e03b9641e57448b9743915eadd0f642e41a41c4d9eaa8b5b861d887b0" dependencies = [ "proc-macro2", "quote", @@ -4525,9 +4525,9 @@ dependencies = [ [[package]] name = "macro_magic_macros" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c24b7896b7c8378ff682bd6c344554b3f629ffefb423ce2a80eba5104a163cba" +checksum = "68cf083ba5ba151ce3230a7c687cb5c890498adae59c85f3be7e8e741a6c9f65" dependencies = [ "macro_magic_core", "quote", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 820eda652c45f..e108f7438bf0f 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -28,7 +28,7 @@ sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } tt-call = "1.0.8" -macro_magic = "0.3.2" +macro_magic = "0.3.3" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index ef9449d3f046a..8bb8451ff0bf9 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -24,7 +24,7 @@ quote = "1.0.26" syn = { version = "2.0.14", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } proc-macro-warning = { version = "0.3.0", default-features = false } -macro_magic = { version = "0.3.2", features = ["proc_support"] } +macro_magic = { version = "0.3.3", features = ["proc_support"] } [features] default = ["std"] diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 812bf4542db6d..5e0c9e6369c29 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -macro_magic = "0.3.2" +macro_magic = "0.3.3" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } From 727a4e70a04ef996d9afc7bb94e4f54462d6887e Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 26 Apr 2023 01:19:55 -0400 Subject: [PATCH 043/116] custom disambiguation_path working as 2nd arg to derive_impl --- frame/examples/basic/src/tests.rs | 5 +- frame/support/procedural/src/derive_impl.rs | 58 ++++++++++++++++++--- frame/support/procedural/src/lib.rs | 43 ++++++++++++--- 3 files changed, 92 insertions(+), 14 deletions(-) diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 4f539e42e6a97..af4c7584440d0 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -50,7 +50,10 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::preludes::testing::TestDefaultConfig)] +#[derive_impl( + frame_system::preludes::testing::TestDefaultConfig, + frame_system::pallet::DefaultConfig +)] impl frame_system::Config for Test { // These are all defined by system as mandatory. type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index c234988d5650d..1ec86637013b9 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -17,10 +17,37 @@ //! Implementation of the `derive_impl` attribute macro. +use derive_syn_parse::Parse; +use macro_magic::mm_core::ForeignPath; use proc_macro2::TokenStream as TokenStream2; -use quote::quote; +use quote::{quote, ToTokens}; use std::collections::HashSet; -use syn::{parse2, parse_quote, Ident, ImplItem, ItemImpl, Path, Result}; +use syn::{ + parse2, parse_quote, spanned::Spanned, token::Comma, Ident, ImplItem, ItemImpl, Path, Result, +}; + +#[derive(Parse)] +pub struct DeriveImplAttrArgs { + pub foreign_path: Path, + _comma: Comma, + pub disambiguation_path: Path, + _comma2: Option, +} + +impl ForeignPath for DeriveImplAttrArgs { + fn foreign_path(&self) -> &Path { + &self.foreign_path + } +} + +impl ToTokens for DeriveImplAttrArgs { + fn to_tokens(&self, tokens: &mut TokenStream2) { + tokens.extend(self.foreign_path.to_token_stream()); + tokens.extend(self._comma.to_token_stream()); + tokens.extend(self.disambiguation_path.to_token_stream()); + tokens.extend(self._comma2.to_token_stream()); + } +} /// Gets the [`Ident`] representation of the given [`ImplItem`], if one exists. Otherwise /// returns [`None`]. @@ -45,11 +72,16 @@ fn impl_item_ident(impl_item: &ImplItem) -> Option { /// This process has the following caveats: /// * Colliding items that have an ident are not copied into `local_impl` /// * Uncolliding items that have an ident are copied into `local_impl` but are qualified as `type -/// #ident = <#foreign_path as #source_crate_path::pallet::DefaultConfig>::#ident;` +/// #ident = <#foreign_path as #disambiguation_path>::#ident;` /// * Items that lack an ident are de-duplicated so only unique items that lack an ident are copied /// into `local_impl`. Items that lack an ident and also exist verbatim in `local_impl` are not /// copied over. -fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl, foreign_path: Path) -> ItemImpl { +fn combine_impls( + local_impl: ItemImpl, + foreign_impl: ItemImpl, + foreign_path: Path, + disambiguation_path: Path, +) -> ItemImpl { let existing_local_keys: HashSet = local_impl .items .iter() @@ -61,7 +93,6 @@ fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl, foreign_path: Pat .filter(|impl_item| impl_item_ident(impl_item).is_none()) .cloned() .collect(); - let source_crate_path = foreign_path.segments.first().unwrap().ident.clone(); let mut final_impl = local_impl; let extended_items = foreign_impl .items @@ -75,7 +106,7 @@ fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl, foreign_path: Pat if matches!(item, ImplItem::Type(_)) { // modify and insert uncolliding type items let modified_item: ImplItem = parse_quote! { - type #ident = <#foreign_path as #source_crate_path::pallet::DefaultConfig>::#ident; + type #ident = <#foreign_path as #disambiguation_path>::#ident; }; Some(modified_item) } else { @@ -106,16 +137,29 @@ fn combine_impls(local_impl: ItemImpl, foreign_impl: ItemImpl, foreign_path: Pat /// `foreign_tokens`: the tokens for the external `impl` statement /// /// `local_tokens`: the tokens for the local `impl` statement this attribute is attached to +/// +/// `disambiguation_path`: the module path of the external trait we will use to qualify +/// defaults imported from the external `impl` statement pub fn derive_impl( foreign_path: TokenStream2, foreign_tokens: TokenStream2, local_tokens: TokenStream2, + disambiguation_path: Path, ) -> Result { let local_impl = parse2::(local_tokens)?; let foreign_impl = parse2::(foreign_tokens)?; let foreign_path = parse2::(foreign_path)?; + let mut disambiguation_path = disambiguation_path; + + let Some(source_crate_path) = foreign_path.segments.first() else { + return Err(syn::Error::new(foreign_path.span(), "foreign_path must have at least one segment")); + }; + let source_crate_path = source_crate_path.ident.clone(); + if disambiguation_path.segments.len() == 1 { + disambiguation_path = parse_quote!(#source_crate_path::pallet::); + } - let combined_impl = combine_impls(local_impl, foreign_impl, foreign_path); + let combined_impl = combine_impls(local_impl, foreign_impl, foreign_path, disambiguation_path); Ok(quote!(#combined_impl)) } diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index a69c824cf311b..bb925cf5d0d8a 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -42,7 +42,7 @@ use proc_macro::TokenStream; use quote::{quote, ToTokens}; use std::{cell::RefCell, str::FromStr}; pub(crate) use storage::INHERENT_INSTANCE_NAME; -use syn::ItemImpl; +use syn::{parse_macro_input, ItemImpl}; thread_local! { /// A global counter, can be used to generate a relatively unique identifier. @@ -779,7 +779,28 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { .into() } -/// This attribtue can be used to derive a test pallet `Config` based on an existing pallet +/// This attribute can be used to derive a full implementation of a trait based on a local +/// partial impl and an external impl containing defaults that can be overriden in the local +/// impl. +/// +/// ## Usage +/// +/// The attribute should be attached to an impl block (in `syn` parlance, an [`ItemImpl`]). +/// This is the impl block that we are injecting with defaults in the event of missing trait +/// items. The sole argument to the attribute should be a path to a valid +/// [`#[register_default_impl]`](`macro@register_default_impl`) call that is attached to an +/// impl containing defaults. +/// +/// ## Expansion +/// +/// The macro will expand to the local impl, with any extra items from the foreign impl that +/// aren't present in the local impl also included. +/// +/// ## Use-Case: Auto-Derive Test Pallet Config Traits +/// +/// Though the machinery behind is general enough to use on any set of traits, a ma +/// +/// This attribute can be used to derive a test pallet `Config` based on an existing pallet /// `Config` that has been marked with [`#[pallet::default_config]`](`macro@default_config`). /// /// The attribute should be attached to an `impl` block that implements a compatible `Config` @@ -790,7 +811,10 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// Consider the following taken from the basic example pallet: /// /// ```ignore -/// #[derive_impl(TestDefaultConfig)] +/// #[derive_impl( +/// frame_system::preludes::testing::TestDefaultConfig, +/// frame_system::pallet::DefaultConfig +/// )] /// impl frame_system::Config for Test { /// // These are all defined by system as mandatory. /// type BaseCallFilter = frame_support::traits::Everything; @@ -876,11 +900,18 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// [`#[pallet::no_default]`], in which case it cannot be overridden, and any attempts to do so /// will result in a compiler error. #[import_tokens_attr(frame_support::macro_magic)] +#[with_custom_parsing(derive_impl::DeriveImplAttrArgs)] #[proc_macro_attribute] pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { - derive_impl::derive_impl(__source_path.into(), attrs.into(), input.into()) - .unwrap_or_else(|r| r.into_compile_error()) - .into() + let custom_attrs = parse_macro_input!(__custom_tokens as derive_impl::DeriveImplAttrArgs); + derive_impl::derive_impl( + __source_path.into(), + attrs.into(), + input.into(), + custom_attrs.disambiguation_path, + ) + .unwrap_or_else(|r| r.into_compile_error()) + .into() } /// The optional attribute `#[pallet::default_config]` can be attached to a `Config` trait From df3b5cef38d6023bfd7fc985f10790293b5b75e2 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 26 Apr 2023 13:33:16 -0400 Subject: [PATCH 044/116] overhaul docs --- frame/support/procedural/src/lib.rs | 73 +++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index bb925cf5d0d8a..7911294ed4481 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -785,30 +785,66 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// /// ## Usage /// -/// The attribute should be attached to an impl block (in `syn` parlance, an [`ItemImpl`]). -/// This is the impl block that we are injecting with defaults in the event of missing trait -/// items. The sole argument to the attribute should be a path to a valid -/// [`#[register_default_impl]`](`macro@register_default_impl`) call that is attached to an -/// impl containing defaults. +/// The attribute should be attached to an impl block (strictly speaking a `syn::ItemImpl`) for +/// which we want to inject defaults in the event of missing trait items in the block. +/// +/// The attribute takes two arguments separated by a comma (and an optional trailing comma +/// after the second argument), with the general form: +/// +/// ```ignore +/// #[derive_impl(foreign_path, disambiguation_path)] +/// impl SomeTrait for SomeStruct { +/// ... +/// } +/// ``` +/// +/// The first argument, called the `foreign_path`, should be the path to an impl registered via +/// [`#[register_default_impl]`](`macro@register_default_impl`) that contains the default trait +/// items we want to potentially inject. +/// +/// The second argument, called the `disambiguation_path`, should be the path to a trait that +/// will be used to qualify all default entries that are injected into the local impl. For +/// example if your `foreign_path` is `some::path::TestTrait` and your `disambiguation_path` is +/// `another::path::DefaultTrait`, any items injected into the local impl will be qualified as +/// `::specific_trait_item`. You can also +/// provide just an ident as the `disambiguation_path`, in which case your +/// `disambiguation_path` will be assumed to be +/// `#your_pallet_crate::pallet::#IdentYouSpecified`. Thus if you want your +/// `disambiguation_path` to be `balances::pallet::DefaultConfig`, you can just specify +/// `DefaultConfig` and the macro will automatically fill in the leading path items. +/// +/// You can also make use of `#[pallet::no_default]` on specific items in your foreign trait +/// that you want to ensure will not be copied over but that you nonetheless want to use +/// locally in the context of the foreign trait and the pallet (or context) in which it is +/// defined /// /// ## Expansion /// /// The macro will expand to the local impl, with any extra items from the foreign impl that -/// aren't present in the local impl also included. +/// aren't present in the local impl also included. In the case of a colliding item, the +/// version of the item that exists in the local impl will be retained. /// -/// ## Use-Case: Auto-Derive Test Pallet Config Traits +/// ## Handling of Unnamed Trait Items /// -/// Though the machinery behind is general enough to use on any set of traits, a ma +/// Items that lack a `syn::Ident` for whatever reason are first checked to see if they +/// exist, verbatim, in the local/destination trait before they are copied over, so you should +/// not need to worry about collisions between identical unnamed items. +/// +/// ## Use-Case: Auto-Derive Test Pallet Config Traits /// -/// This attribute can be used to derive a test pallet `Config` based on an existing pallet -/// `Config` that has been marked with [`#[pallet::default_config]`](`macro@default_config`). +/// The `#[derive_imp(..)]` attribute can be used to derive a test pallet `Config` based on an +/// existing pallet `Config` that has been marked with +/// [`#[pallet::default_config]`](`macro@default_config`) (which under the hood, generates a +/// `DefaultConfig` trait in the pallet in which the macro was invoked). /// -/// The attribute should be attached to an `impl` block that implements a compatible `Config` -/// such as `frame_system::Config` for a test/mock runtime, and should receive as its only -/// argument the path to a `DefaultConfig` impl that has been registered via -/// [`#[register_default_impl]`](`macro@register_default_impl`). +/// In this case, the `#[derive_impl(..)]` attribute should be attached to an `impl` block that +/// implements a compatible `Config` such as `frame_system::Config` for a test/mock runtime, and +/// should receive as its first argument the path to a `DefaultConfig` impl that has been registered +/// via [`#[register_default_impl]`](`macro@register_default_impl`), and as its second argument, +/// the path to the auto-generated `DefaultConfig` for the existing pallet `Config` we want to +/// base our test config off of. /// -/// Consider the following taken from the basic example pallet: +/// Consider the following taken from the `basic` example pallet: /// /// ```ignore /// #[derive_impl( @@ -829,8 +865,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// } /// ``` /// -/// where `TestDefaultConfig` was defined and registered as -/// follows: +/// where `TestDefaultConfig` was defined and registered as follows: /// /// ```ignore /// pub struct TestDefaultConfig {} @@ -897,8 +932,8 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// [`#[pallet::default_config]`](`macro@default_config`) are automatically copied from the /// foreign trait (in this case `TestDefaultConfig`) into the local trait impl (in this case /// `Test`), unless the trait item in the local trait impl is marked with -/// [`#[pallet::no_default]`], in which case it cannot be overridden, and any attempts to do so -/// will result in a compiler error. +/// [`#[pallet::no_default]`](`macro@default_config`), in which case it cannot be overridden, +/// and any attempts to do so will result in a compiler error. #[import_tokens_attr(frame_support::macro_magic)] #[with_custom_parsing(derive_impl::DeriveImplAttrArgs)] #[proc_macro_attribute] From 4a33e99ddc9b4bdca87a5ad06bbe951e69305548 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 27 Apr 2023 10:58:54 -0400 Subject: [PATCH 045/116] fixes, ident-style paths shortcut working --- frame/examples/basic/src/tests.rs | 5 +---- frame/support/procedural/src/derive_impl.rs | 20 +++++++++++++++++--- frame/system/src/lib.rs | 1 - 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index af4c7584440d0..06805902e39c9 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -50,10 +50,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl( - frame_system::preludes::testing::TestDefaultConfig, - frame_system::pallet::DefaultConfig -)] +#[derive_impl(frame_system::preludes::testing::TestDefaultConfig, DefaultConfig)] impl frame_system::Config for Test { // These are all defined by system as mandatory. type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 1ec86637013b9..ca550789372c1 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -29,7 +29,7 @@ use syn::{ #[derive(Parse)] pub struct DeriveImplAttrArgs { pub foreign_path: Path, - _comma: Comma, + _comma1: Comma, pub disambiguation_path: Path, _comma2: Option, } @@ -43,12 +43,26 @@ impl ForeignPath for DeriveImplAttrArgs { impl ToTokens for DeriveImplAttrArgs { fn to_tokens(&self, tokens: &mut TokenStream2) { tokens.extend(self.foreign_path.to_token_stream()); - tokens.extend(self._comma.to_token_stream()); + tokens.extend(self._comma1.to_token_stream()); tokens.extend(self.disambiguation_path.to_token_stream()); tokens.extend(self._comma2.to_token_stream()); } } +#[test] +fn test_derive_impl_attr_args_parsing() { + parse2::(quote!(some::path::TestDefaultConfig, some::path::DefaultConfig)) + .unwrap(); + parse2::(quote!( + frame_system::preludes::testing::TestDefaultConfig, + DefaultConfig + )) + .unwrap(); + parse2::(quote!(Something, some::path::DefaultConfig)).unwrap(); + parse2::(quote!(Something, DefaultConfig)).unwrap(); + assert!(parse2::(quote!(DefaultConfig)).is_err()); +} + /// Gets the [`Ident`] representation of the given [`ImplItem`], if one exists. Otherwise /// returns [`None`]. /// @@ -156,7 +170,7 @@ pub fn derive_impl( }; let source_crate_path = source_crate_path.ident.clone(); if disambiguation_path.segments.len() == 1 { - disambiguation_path = parse_quote!(#source_crate_path::pallet::); + disambiguation_path = parse_quote!(#source_crate_path::pallet::#disambiguation_path); } let combined_impl = combine_impls(local_impl, foreign_impl, foreign_path, disambiguation_path); diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 1ec1e6aa9b629..1fa33db162516 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -246,7 +246,6 @@ pub mod pallet { /// The basic call filter to use in Origin. All origins are built with this filter as base, /// except Root. #[pallet::no_default] - // enum Everything is a reasonable default, but it is not possible. type BaseCallFilter: Contains; /// Block & extrinsics weights: base values and limits. From a9413d34b400b174c83a018a240ca0fcb66bfdeb Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 27 Apr 2023 11:47:08 -0400 Subject: [PATCH 046/116] remove ident-style shortcut because it makes testing difficult --- frame/examples/basic/src/tests.rs | 5 ++++- frame/support/procedural/src/derive_impl.rs | 14 ++------------ frame/support/procedural/src/lib.rs | 7 +------ 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 06805902e39c9..af4c7584440d0 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -50,7 +50,10 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::preludes::testing::TestDefaultConfig, DefaultConfig)] +#[derive_impl( + frame_system::preludes::testing::TestDefaultConfig, + frame_system::pallet::DefaultConfig +)] impl frame_system::Config for Test { // These are all defined by system as mandatory. type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index ca550789372c1..27d1ef95d8d3b 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -22,9 +22,7 @@ use macro_magic::mm_core::ForeignPath; use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens}; use std::collections::HashSet; -use syn::{ - parse2, parse_quote, spanned::Spanned, token::Comma, Ident, ImplItem, ItemImpl, Path, Result, -}; +use syn::{parse2, parse_quote, token::Comma, Ident, ImplItem, ItemImpl, Path, Result}; #[derive(Parse)] pub struct DeriveImplAttrArgs { @@ -163,15 +161,7 @@ pub fn derive_impl( let local_impl = parse2::(local_tokens)?; let foreign_impl = parse2::(foreign_tokens)?; let foreign_path = parse2::(foreign_path)?; - let mut disambiguation_path = disambiguation_path; - - let Some(source_crate_path) = foreign_path.segments.first() else { - return Err(syn::Error::new(foreign_path.span(), "foreign_path must have at least one segment")); - }; - let source_crate_path = source_crate_path.ident.clone(); - if disambiguation_path.segments.len() == 1 { - disambiguation_path = parse_quote!(#source_crate_path::pallet::#disambiguation_path); - } + let disambiguation_path = disambiguation_path; let combined_impl = combine_impls(local_impl, foreign_impl, foreign_path, disambiguation_path); diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 7911294ed4481..a36d3ccadfc8c 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -806,12 +806,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// will be used to qualify all default entries that are injected into the local impl. For /// example if your `foreign_path` is `some::path::TestTrait` and your `disambiguation_path` is /// `another::path::DefaultTrait`, any items injected into the local impl will be qualified as -/// `::specific_trait_item`. You can also -/// provide just an ident as the `disambiguation_path`, in which case your -/// `disambiguation_path` will be assumed to be -/// `#your_pallet_crate::pallet::#IdentYouSpecified`. Thus if you want your -/// `disambiguation_path` to be `balances::pallet::DefaultConfig`, you can just specify -/// `DefaultConfig` and the macro will automatically fill in the leading path items. +/// `::specific_trait_item`. /// /// You can also make use of `#[pallet::no_default]` on specific items in your foreign trait /// that you want to ensure will not be copied over but that you nonetheless want to use From ec34f5813b8442f5aea2d1e43c3754e8944e7241 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 27 Apr 2023 12:21:25 -0400 Subject: [PATCH 047/116] add passing UI tests for derive_impl --- Cargo.lock | 1 + frame/support/test/Cargo.toml | 1 + frame/support/test/tests/derive_impl_ui.rs | 37 ++++++++++++++ .../derive_impl_ui/pass/basic_overriding.rs | 48 +++++++++++++++++++ .../pass/macro_magic_working.rs | 18 +++++++ 5 files changed, 105 insertions(+) create mode 100644 frame/support/test/tests/derive_impl_ui.rs create mode 100644 frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs create mode 100644 frame/support/test/tests/derive_impl_ui/pass/macro_magic_working.rs diff --git a/Cargo.lock b/Cargo.lock index 328e00f7d23e8..7ab260483b739 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2535,6 +2535,7 @@ dependencies = [ "sp-state-machine", "sp-std", "sp-version", + "static_assertions", "trybuild", ] diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 9564b6a04d7e7..5996aef8045cb 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -12,6 +12,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +static_assertions = "1.1.0" serde = { version = "1.0.136", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } diff --git a/frame/support/test/tests/derive_impl_ui.rs b/frame/support/test/tests/derive_impl_ui.rs new file mode 100644 index 0000000000000..301f3559bd8f6 --- /dev/null +++ b/frame/support/test/tests/derive_impl_ui.rs @@ -0,0 +1,37 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(not(feature = "disable-ui-tests"))] +#![cfg(test)] + +#[test] +fn derive_impl_ui() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if std::env::var("RUN_UI_TESTS").is_err() { + return + } + + // As trybuild is using `cargo check`, we don't need the real WASM binaries. + std::env::set_var("SKIP_WASM_BUILD", "1"); + + // Deny all warnings since we emit warnings as part of a Pallet's UI. + std::env::set_var("RUSTFLAGS", "--deny warnings"); + + let t = trybuild::TestCases::new(); + t.compile_fail("tests/derive_impl_ui/*.rs"); + t.pass("tests/derive_impl_ui/pass/*.rs"); +} diff --git a/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs b/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs new file mode 100644 index 0000000000000..afb55de82c246 --- /dev/null +++ b/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs @@ -0,0 +1,48 @@ +use frame_support::*; +use static_assertions::assert_type_eq_all; + +pub trait Animal { + type Locomotion; + type Diet; + type SleepingStrategy; + type Environment; + + fn animal_name() -> &'static str; +} + +pub type RunsOnFourLegs = (usize, usize, usize, usize); +pub type RunsOnTwoLegs = (usize, usize); +pub type Swims = isize; +pub type Diurnal = bool; +pub type Omnivore = char; +pub type Land = ((), ()); +pub type Sea = ((), (), ()); + +pub struct FourLeggedAnimal {} + +#[register_default_impl(FourLeggedAnimal)] +impl Animal for FourLeggedAnimal { + type Locomotion = RunsOnFourLegs; + type Diet = Omnivore; + type SleepingStrategy = Diurnal; + type Environment = Land; + + fn animal_name() -> &'static str { + "A Four-Legged Animal" + } +} + +pub struct AcquaticMammal {} + +#[derive_impl(FourLeggedAnimal, Animal)] +impl Animal for AcquaticMammal { + type Locomotion = (Swims, RunsOnFourLegs); + type Environment = (Land, Sea); +} + +assert_type_eq_all!(::Locomotion, (Swims, RunsOnFourLegs)); +assert_type_eq_all!(::Environment, (Land, Sea)); +assert_type_eq_all!(::Diet, Omnivore); +assert_type_eq_all!(::SleepingStrategy, Diurnal); + +fn main() {} diff --git a/frame/support/test/tests/derive_impl_ui/pass/macro_magic_working.rs b/frame/support/test/tests/derive_impl_ui/pass/macro_magic_working.rs new file mode 100644 index 0000000000000..ec09bd15e0173 --- /dev/null +++ b/frame/support/test/tests/derive_impl_ui/pass/macro_magic_working.rs @@ -0,0 +1,18 @@ +#[frame_support::macro_magic::export_tokens] +struct MyCoolStruct { + field: u32, +} + +// create a test receiver since `proc_support` isn't enabled so we're on our own in terms of +// what we can call +macro_rules! receiver { + ($_tokens_var:ident, $($tokens:tt)*) => { + stringify!($($tokens)*) + }; +} + +fn main() { + let _instance: MyCoolStruct = MyCoolStruct { field: 3 }; + let _str = __export_tokens_tt_my_cool_struct!(tokens, receiver); + // this compiling demonstrates that macro_magic is working properly +} From 52152a500705c4200c298945dfaca011847028b6 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 27 Apr 2023 16:28:13 -0400 Subject: [PATCH 048/116] switch to `ForeignPath as DisambiguationPath` syntax + update docs --- frame/examples/basic/src/tests.rs | 5 +--- frame/support/procedural/src/derive_impl.rs | 30 ++++++++++++++----- frame/support/procedural/src/lib.rs | 29 ++++++++++-------- .../derive_impl_ui/pass/basic_overriding.rs | 23 +++++++++++++- 4 files changed, 61 insertions(+), 26 deletions(-) diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index af4c7584440d0..8b5a2b465f8bf 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -50,10 +50,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl( - frame_system::preludes::testing::TestDefaultConfig, - frame_system::pallet::DefaultConfig -)] +#[derive_impl(frame_system::preludes::testing::TestDefaultConfig as frame_system::pallet::DefaultConfig)] impl frame_system::Config for Test { // These are all defined by system as mandatory. type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 27d1ef95d8d3b..39613c57c1c19 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -22,14 +22,14 @@ use macro_magic::mm_core::ForeignPath; use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens}; use std::collections::HashSet; -use syn::{parse2, parse_quote, token::Comma, Ident, ImplItem, ItemImpl, Path, Result}; +use syn::{parse2, parse_quote, spanned::Spanned, Ident, ImplItem, ItemImpl, Path, Result, Token}; #[derive(Parse)] pub struct DeriveImplAttrArgs { pub foreign_path: Path, - _comma1: Comma, - pub disambiguation_path: Path, - _comma2: Option, + _as: Option, + #[parse_if(_as.is_some())] + pub disambiguation_path: Option, } impl ForeignPath for DeriveImplAttrArgs { @@ -41,9 +41,8 @@ impl ForeignPath for DeriveImplAttrArgs { impl ToTokens for DeriveImplAttrArgs { fn to_tokens(&self, tokens: &mut TokenStream2) { tokens.extend(self.foreign_path.to_token_stream()); - tokens.extend(self._comma1.to_token_stream()); + tokens.extend(self._as.to_token_stream()); tokens.extend(self.disambiguation_path.to_token_stream()); - tokens.extend(self._comma2.to_token_stream()); } } @@ -156,13 +155,28 @@ pub fn derive_impl( foreign_path: TokenStream2, foreign_tokens: TokenStream2, local_tokens: TokenStream2, - disambiguation_path: Path, + disambiguation_path: Option, ) -> Result { let local_impl = parse2::(local_tokens)?; let foreign_impl = parse2::(foreign_tokens)?; let foreign_path = parse2::(foreign_path)?; - let disambiguation_path = disambiguation_path; + // have disambiguation_path default to the item being impl'd in the foreign impl if we + // don't specify an `as [disambiguation_path]` in the macro attr + let disambiguation_path = match disambiguation_path { + Some(disambiguation_path) => disambiguation_path, + None => { + let Some((_, foreign_impl_path, _)) = foreign_impl.clone().trait_ else { + return Err( + syn::Error::new(foreign_impl.span(), + "Impl statement must have a defined type being implemented for a defined type such as `impl A for B`") + ); + }; + foreign_impl_path + }, + }; + + // generate the combined impl let combined_impl = combine_impls(local_impl, foreign_impl, foreign_path, disambiguation_path); Ok(quote!(#combined_impl)) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index a36d3ccadfc8c..3ddc5342eb6aa 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -788,25 +788,31 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// The attribute should be attached to an impl block (strictly speaking a `syn::ItemImpl`) for /// which we want to inject defaults in the event of missing trait items in the block. /// -/// The attribute takes two arguments separated by a comma (and an optional trailing comma -/// after the second argument), with the general form: +/// The attribute takes two arguments separated by an `as` with the general form: /// /// ```ignore -/// #[derive_impl(foreign_path, disambiguation_path)] +/// #[derive_impl(foreign_path as disambiguation_path)] /// impl SomeTrait for SomeStruct { /// ... /// } /// ``` /// -/// The first argument, called the `foreign_path`, should be the path to an impl registered via +/// The `foreign_path` should be the path to an impl registered via /// [`#[register_default_impl]`](`macro@register_default_impl`) that contains the default trait /// items we want to potentially inject. /// -/// The second argument, called the `disambiguation_path`, should be the path to a trait that -/// will be used to qualify all default entries that are injected into the local impl. For -/// example if your `foreign_path` is `some::path::TestTrait` and your `disambiguation_path` is -/// `another::path::DefaultTrait`, any items injected into the local impl will be qualified as -/// `::specific_trait_item`. +/// The `disambiguation_path` should be the path to a trait that will be used to qualify all +/// default entries that are injected into the local impl. For example if your `foreign_path` +/// is `some::path::TestTrait` and your `disambiguation_path` is `another::path::DefaultTrait`, +/// any items injected into the local impl will be qualified as `::specific_trait_item`. +/// +/// Optionally, you may omit the `as disambiguation_path` portion, in which case the +/// `disambiguation_path` will internally default to `A` from the `impl A for B` part of the +/// foreign impl. This is useful for scenarios where all of the relevant types are already in +/// scope. +/// +/// Conversely, the `foreign_path` argument is required and cannot be omitted. /// /// You can also make use of `#[pallet::no_default]` on specific items in your foreign trait /// that you want to ensure will not be copied over but that you nonetheless want to use @@ -842,10 +848,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// Consider the following taken from the `basic` example pallet: /// /// ```ignore -/// #[derive_impl( -/// frame_system::preludes::testing::TestDefaultConfig, -/// frame_system::pallet::DefaultConfig -/// )] +/// #[derive_impl(frame_system::preludes::testing::TestDefaultConfig as frame_system::pallet::DefaultConfig)] /// impl frame_system::Config for Test { /// // These are all defined by system as mandatory. /// type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs b/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs index afb55de82c246..336ddc315f8cb 100644 --- a/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs +++ b/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs @@ -14,9 +14,11 @@ pub type RunsOnFourLegs = (usize, usize, usize, usize); pub type RunsOnTwoLegs = (usize, usize); pub type Swims = isize; pub type Diurnal = bool; +pub type Nocturnal = Option; pub type Omnivore = char; pub type Land = ((), ()); pub type Sea = ((), (), ()); +pub type Carnivore = (char, char); pub struct FourLeggedAnimal {} @@ -34,7 +36,8 @@ impl Animal for FourLeggedAnimal { pub struct AcquaticMammal {} -#[derive_impl(FourLeggedAnimal, Animal)] +// without omitting the `as X` +#[derive_impl(FourLeggedAnimal as Animal)] impl Animal for AcquaticMammal { type Locomotion = (Swims, RunsOnFourLegs); type Environment = (Land, Sea); @@ -45,4 +48,22 @@ assert_type_eq_all!(::Environment, (Land, Sea)); assert_type_eq_all!(::Diet, Omnivore); assert_type_eq_all!(::SleepingStrategy, Diurnal); +pub struct Lion {} + +// test omitting the `as X` +#[derive_impl(FourLeggedAnimal)] +impl Animal for Lion { + type Diet = Carnivore; + type SleepingStrategy = Nocturnal; + + fn animal_name() -> &'static str { + "Lion" + } +} + +assert_type_eq_all!(::Diet, Carnivore); +assert_type_eq_all!(::SleepingStrategy, Nocturnal); +assert_type_eq_all!(::Environment, Land); +assert_type_eq_all!(::Locomotion, RunsOnFourLegs); + fn main() {} From e191aa98ba98bf9143c7f773322abd96df101696 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 27 Apr 2023 21:29:05 -0400 Subject: [PATCH 049/116] add UI test for bad foreign path --- .../tests/derive_impl_ui/bad_foreign_path.rs | 48 +++++++++++++++++++ .../derive_impl_ui/bad_foreign_path.stderr | 7 +++ 2 files changed, 55 insertions(+) create mode 100644 frame/support/test/tests/derive_impl_ui/bad_foreign_path.rs create mode 100644 frame/support/test/tests/derive_impl_ui/bad_foreign_path.stderr diff --git a/frame/support/test/tests/derive_impl_ui/bad_foreign_path.rs b/frame/support/test/tests/derive_impl_ui/bad_foreign_path.rs new file mode 100644 index 0000000000000..2badd1830033b --- /dev/null +++ b/frame/support/test/tests/derive_impl_ui/bad_foreign_path.rs @@ -0,0 +1,48 @@ +use frame_support::*; + +pub trait Animal { + type Locomotion; + type Diet; + type SleepingStrategy; + type Environment; + + fn animal_name() -> &'static str; +} + +pub type RunsOnFourLegs = (usize, usize, usize, usize); +pub type RunsOnTwoLegs = (usize, usize); +pub type Swims = isize; +pub type Diurnal = bool; +pub type Nocturnal = Option; +pub type Omnivore = char; +pub type Land = ((), ()); +pub type Sea = ((), (), ()); +pub type Carnivore = (char, char); + +pub struct FourLeggedAnimal {} + +#[register_default_impl(FourLeggedAnimal)] +impl Animal for FourLeggedAnimal { + type Locomotion = RunsOnFourLegs; + type Diet = Omnivore; + type SleepingStrategy = Diurnal; + type Environment = Land; + + fn animal_name() -> &'static str { + "A Four-Legged Animal" + } +} + +pub struct AcquaticMammal {} + +// Should throw: `error: cannot find macro `__export_tokens_tt_tiger` in this scope` +// +// Note that there is really no better way to clean up this error, tt_call suffers from the +// same downside but this is really the only rough edge when using macro magic. +#[derive_impl(Tiger as Animal)] +impl Animal for AcquaticMammal { + type Locomotion = (Swims, RunsOnFourLegs); + type Environment = (Land, Sea); +} + +fn main() {} diff --git a/frame/support/test/tests/derive_impl_ui/bad_foreign_path.stderr b/frame/support/test/tests/derive_impl_ui/bad_foreign_path.stderr new file mode 100644 index 0000000000000..d1e348e15faf4 --- /dev/null +++ b/frame/support/test/tests/derive_impl_ui/bad_foreign_path.stderr @@ -0,0 +1,7 @@ +error: cannot find macro `__export_tokens_tt_tiger` in this scope + --> tests/derive_impl_ui/bad_foreign_path.rs:42:1 + | +42 | #[derive_impl(Tiger as Animal)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `frame_support::macro_magic::forward_tokens` (in Nightly builds, run with -Z macro-backtrace for more info) From cc9ee82e2c7cbb3bff28f9e0752707b296ef0f59 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 27 Apr 2023 21:36:20 -0400 Subject: [PATCH 050/116] add UI test for bad disambiguation path --- .../derive_impl_ui/bad_disambiguation_path.rs | 44 +++++++++++++++++++ .../bad_disambiguation_path.stderr | 16 +++++++ 2 files changed, 60 insertions(+) create mode 100644 frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.rs create mode 100644 frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.stderr diff --git a/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.rs b/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.rs new file mode 100644 index 0000000000000..adc5df23a759a --- /dev/null +++ b/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.rs @@ -0,0 +1,44 @@ +use frame_support::*; + +pub trait Animal { + type Locomotion; + type Diet; + type SleepingStrategy; + type Environment; + + fn animal_name() -> &'static str; +} + +pub type RunsOnFourLegs = (usize, usize, usize, usize); +pub type RunsOnTwoLegs = (usize, usize); +pub type Swims = isize; +pub type Diurnal = bool; +pub type Nocturnal = Option; +pub type Omnivore = char; +pub type Land = ((), ()); +pub type Sea = ((), (), ()); +pub type Carnivore = (char, char); + +pub struct FourLeggedAnimal {} + +#[register_default_impl(FourLeggedAnimal)] +impl Animal for FourLeggedAnimal { + type Locomotion = RunsOnFourLegs; + type Diet = Omnivore; + type SleepingStrategy = Diurnal; + type Environment = Land; + + fn animal_name() -> &'static str { + "A Four-Legged Animal" + } +} + +pub struct AcquaticMammal {} + +#[derive_impl(FourLeggedAnimal as Insect)] +impl Animal for AcquaticMammal { + type Locomotion = (Swims, RunsOnFourLegs); + type Environment = (Land, Sea); +} + +fn main() {} diff --git a/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.stderr b/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.stderr new file mode 100644 index 0000000000000..b2cc0cbd963c4 --- /dev/null +++ b/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.stderr @@ -0,0 +1,16 @@ +error[E0405]: cannot find trait `Insect` in this scope + --> tests/derive_impl_ui/bad_disambiguation_path.rs:24:1 + | +24 | / #[register_default_impl(FourLeggedAnimal)] +25 | | impl Animal for FourLeggedAnimal { +26 | | type Locomotion = RunsOnFourLegs; +27 | | type Diet = Omnivore; +... | +37 | | +38 | | #[derive_impl(FourLeggedAnimal as Insect)] + | | -----------------------------------------^ + | |_|________________________________________| + | | not found in this scope + | in this procedural macro expansion + | + = note: this error originates in the macro `__import_tokens_attr_derive_impl_inner` which comes from the expansion of the attribute macro `derive_impl` (in Nightly builds, run with -Z macro-backtrace for more info) From 5119cf5ee28f14740621f270dd6bab8c982e23a0 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 27 Apr 2023 21:41:10 -0400 Subject: [PATCH 051/116] add UI test for missing disambiguation path --- .../missing_disambiguation_path.rs | 44 +++++++++++++++++++ .../missing_disambiguation_path.stderr | 7 +++ 2 files changed, 51 insertions(+) create mode 100644 frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.rs create mode 100644 frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.stderr diff --git a/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.rs b/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.rs new file mode 100644 index 0000000000000..21f1cc32009a5 --- /dev/null +++ b/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.rs @@ -0,0 +1,44 @@ +use frame_support::*; + +pub trait Animal { + type Locomotion; + type Diet; + type SleepingStrategy; + type Environment; + + fn animal_name() -> &'static str; +} + +pub type RunsOnFourLegs = (usize, usize, usize, usize); +pub type RunsOnTwoLegs = (usize, usize); +pub type Swims = isize; +pub type Diurnal = bool; +pub type Nocturnal = Option; +pub type Omnivore = char; +pub type Land = ((), ()); +pub type Sea = ((), (), ()); +pub type Carnivore = (char, char); + +pub struct FourLeggedAnimal {} + +#[register_default_impl(FourLeggedAnimal)] +impl Animal for FourLeggedAnimal { + type Locomotion = RunsOnFourLegs; + type Diet = Omnivore; + type SleepingStrategy = Diurnal; + type Environment = Land; + + fn animal_name() -> &'static str { + "A Four-Legged Animal" + } +} + +pub struct AcquaticMammal {} + +#[derive_impl(FourLeggedAnimal as)] +impl Animal for AcquaticMammal { + type Locomotion = (Swims, RunsOnFourLegs); + type Environment = (Land, Sea); +} + +fn main() {} diff --git a/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.stderr b/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.stderr new file mode 100644 index 0000000000000..85cd94ae08ae7 --- /dev/null +++ b/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.stderr @@ -0,0 +1,7 @@ +error: unexpected end of input, expected identifier + --> tests/derive_impl_ui/missing_disambiguation_path.rs:38:1 + | +38 | #[derive_impl(FourLeggedAnimal as)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `derive_impl` (in Nightly builds, run with -Z macro-backtrace for more info) From 2fd5cc5ad50bb5e6d257487f66d2c60f9e3d9818 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 27 Apr 2023 21:56:52 -0400 Subject: [PATCH 052/116] add UI test for attached to non impl --- .../derive_impl_ui/attached_to_non_impl.rs | 41 +++++++++++++++++++ .../attached_to_non_impl.stderr | 15 +++++++ 2 files changed, 56 insertions(+) create mode 100644 frame/support/test/tests/derive_impl_ui/attached_to_non_impl.rs create mode 100644 frame/support/test/tests/derive_impl_ui/attached_to_non_impl.stderr diff --git a/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.rs b/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.rs new file mode 100644 index 0000000000000..3b27916933865 --- /dev/null +++ b/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.rs @@ -0,0 +1,41 @@ +use frame_support::*; + +pub trait Animal { + type Locomotion; + type Diet; + type SleepingStrategy; + type Environment; + + fn animal_name() -> &'static str; +} + +pub type RunsOnFourLegs = (usize, usize, usize, usize); +pub type RunsOnTwoLegs = (usize, usize); +pub type Swims = isize; +pub type Diurnal = bool; +pub type Nocturnal = Option; +pub type Omnivore = char; +pub type Land = ((), ()); +pub type Sea = ((), (), ()); +pub type Carnivore = (char, char); + +pub struct FourLeggedAnimal {} + +#[register_default_impl(FourLeggedAnimal)] +impl Animal for FourLeggedAnimal { + type Locomotion = RunsOnFourLegs; + type Diet = Omnivore; + type SleepingStrategy = Diurnal; + type Environment = Land; + + fn animal_name() -> &'static str { + "A Four-Legged Animal" + } +} + +pub struct AcquaticMammal {} + +#[derive_impl(FourLeggedAnimal as Animal)] +struct Something {} + +fn main() {} diff --git a/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.stderr b/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.stderr new file mode 100644 index 0000000000000..94aee2442513a --- /dev/null +++ b/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.stderr @@ -0,0 +1,15 @@ +error: expected `impl` + --> tests/derive_impl_ui/attached_to_non_impl.rs:24:1 + | +24 | / #[register_default_impl(FourLeggedAnimal)] +25 | | impl Animal for FourLeggedAnimal { +26 | | type Locomotion = RunsOnFourLegs; +27 | | type Diet = Omnivore; +... | +37 | | +38 | | #[derive_impl(FourLeggedAnimal as Animal)] + | |_-----------------------------------------^ + | | + | in this procedural macro expansion + | + = note: this error originates in the macro `__import_tokens_attr_derive_impl_inner` which comes from the expansion of the attribute macro `derive_impl` (in Nightly builds, run with -Z macro-backtrace for more info) From 814176e71ebed4f9d3f6f586056a17b11665661c Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 27 Apr 2023 22:14:09 -0400 Subject: [PATCH 053/116] fix derive_impl_attr_args_parsing test --- frame/support/procedural/src/derive_impl.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 39613c57c1c19..8b695857dd02b 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -48,16 +48,19 @@ impl ToTokens for DeriveImplAttrArgs { #[test] fn test_derive_impl_attr_args_parsing() { - parse2::(quote!(some::path::TestDefaultConfig, some::path::DefaultConfig)) - .unwrap(); parse2::(quote!( - frame_system::preludes::testing::TestDefaultConfig, - DefaultConfig + some::path::TestDefaultConfig as some::path::DefaultConfig )) .unwrap(); - parse2::(quote!(Something, some::path::DefaultConfig)).unwrap(); - parse2::(quote!(Something, DefaultConfig)).unwrap(); - assert!(parse2::(quote!(DefaultConfig)).is_err()); + parse2::(quote!( + frame_system::preludes::testing::TestDefaultConfig as DefaultConfig + )) + .unwrap(); + parse2::(quote!(Something as some::path::DefaultConfig)).unwrap(); + parse2::(quote!(Something as DefaultConfig)).unwrap(); + parse2::(quote!(DefaultConfig)).unwrap(); + assert!(parse2::(quote!()).is_err()); + assert!(parse2::(quote!(Config Config)).is_err()); } /// Gets the [`Ident`] representation of the given [`ImplItem`], if one exists. Otherwise From d4cf31ef3402e5dfa1ac02df61b315293a72fd0f Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 27 Apr 2023 22:15:38 -0400 Subject: [PATCH 054/116] move tests to bottom --- frame/support/procedural/src/derive_impl.rs | 34 ++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 8b695857dd02b..0972fbc9f94c9 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -46,23 +46,6 @@ impl ToTokens for DeriveImplAttrArgs { } } -#[test] -fn test_derive_impl_attr_args_parsing() { - parse2::(quote!( - some::path::TestDefaultConfig as some::path::DefaultConfig - )) - .unwrap(); - parse2::(quote!( - frame_system::preludes::testing::TestDefaultConfig as DefaultConfig - )) - .unwrap(); - parse2::(quote!(Something as some::path::DefaultConfig)).unwrap(); - parse2::(quote!(Something as DefaultConfig)).unwrap(); - parse2::(quote!(DefaultConfig)).unwrap(); - assert!(parse2::(quote!()).is_err()); - assert!(parse2::(quote!(Config Config)).is_err()); -} - /// Gets the [`Ident`] representation of the given [`ImplItem`], if one exists. Otherwise /// returns [`None`]. /// @@ -184,3 +167,20 @@ pub fn derive_impl( Ok(quote!(#combined_impl)) } + +#[test] +fn test_derive_impl_attr_args_parsing() { + parse2::(quote!( + some::path::TestDefaultConfig as some::path::DefaultConfig + )) + .unwrap(); + parse2::(quote!( + frame_system::preludes::testing::TestDefaultConfig as DefaultConfig + )) + .unwrap(); + parse2::(quote!(Something as some::path::DefaultConfig)).unwrap(); + parse2::(quote!(Something as DefaultConfig)).unwrap(); + parse2::(quote!(DefaultConfig)).unwrap(); + assert!(parse2::(quote!()).is_err()); + assert!(parse2::(quote!(Config Config)).is_err()); +} From 53bfe6dae6bbefd44b691149cfdb466d0716a86d Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 27 Apr 2023 23:02:10 -0400 Subject: [PATCH 055/116] fix nightly issue --- frame/support/test/tests/derive_impl_ui.rs | 1 + .../test/tests/derive_impl_ui/bad_disambiguation_path.stderr | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/frame/support/test/tests/derive_impl_ui.rs b/frame/support/test/tests/derive_impl_ui.rs index 301f3559bd8f6..ee219d0670aaf 100644 --- a/frame/support/test/tests/derive_impl_ui.rs +++ b/frame/support/test/tests/derive_impl_ui.rs @@ -18,6 +18,7 @@ #![cfg(not(feature = "disable-ui-tests"))] #![cfg(test)] +#[rustversion::attr(not(stable), ignore)] #[test] fn derive_impl_ui() { // Only run the ui tests when `RUN_UI_TESTS` is set. diff --git a/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.stderr b/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.stderr index b2cc0cbd963c4..dd098d82c1e9b 100644 --- a/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.stderr +++ b/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.stderr @@ -1,4 +1,4 @@ -error[E0405]: cannot find trait `Insect` in this scope +error[E0433]: failed to resolve: use of undeclared type `Insect` --> tests/derive_impl_ui/bad_disambiguation_path.rs:24:1 | 24 | / #[register_default_impl(FourLeggedAnimal)] @@ -10,7 +10,7 @@ error[E0405]: cannot find trait `Insect` in this scope 38 | | #[derive_impl(FourLeggedAnimal as Insect)] | | -----------------------------------------^ | |_|________________________________________| - | | not found in this scope + | | use of undeclared type `Insect` | in this procedural macro expansion | = note: this error originates in the macro `__import_tokens_attr_derive_impl_inner` which comes from the expansion of the attribute macro `derive_impl` (in Nightly builds, run with -Z macro-backtrace for more info) From 9bf5328c296acc6969bf198b398dad19d6c74dfd Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 28 Apr 2023 11:57:18 -0400 Subject: [PATCH 056/116] add doc notes on importing/re-exporting --- frame/support/procedural/src/lib.rs | 30 ++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 607e15b12a56b..d94ed739782a9 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -821,11 +821,35 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// locally in the context of the foreign trait and the pallet (or context) in which it is /// defined /// +/// ## Importing & Re-Exporting +/// +/// Since `#[derive_impl(..)]` is a +/// [`macro_magic`](https://docs.rs/macro_magic/latest/macro_magic/)-based attribute macro, +/// special care must be taken when importing and re-exporting it. Glob imports will work +/// properly, such as `use frame_support::*` to bring `derive_impl` into scope, however any +/// other use statements involving `derive_impl` should have +/// [`#[macro_magic::use_attr]`](https://docs.rs/macro_magic/latest/macro_magic/attr.use_attr.html) +/// attached or your use statement will fail to fully bring the macro into scope. +/// +/// This brings `derive_impl` into scope in the current context: +/// ```ignore +/// #[use_attr] +/// use frame_support::derive_impl; +/// ``` +/// +/// This brings `derive_impl` into scope and publicly re-exports it from the current context: +/// ```ignore +/// #[use_attr] +/// pub use frame_support::derive_impl; +/// ``` +/// /// ## Expansion /// -/// The macro will expand to the local impl, with any extra items from the foreign impl that -/// aren't present in the local impl also included. In the case of a colliding item, the -/// version of the item that exists in the local impl will be retained. +/// The `#[derive_impl(foreign_path as disambiguation_path)]` attribute will expand to the +/// local impl, with any extra items from the foreign impl that aren't present in the local +/// impl also included. In the case of a colliding trait item, the version of the item that +/// exists in the local impl will be retained. All imported items are qualified by the +/// `disambiguation_path`, as discussed above. /// /// ## Handling of Unnamed Trait Items /// From 97de1123962e2a17df9f5dc725797b19a29f43ac Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 28 Apr 2023 12:30:39 -0400 Subject: [PATCH 057/116] remove explicit use of macro_magic::use_attr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- frame/support/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 6954958ce9f9e..2abfe9490b292 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -32,7 +32,6 @@ /// Export ourself as `frame_support` to make tests happy. extern crate self as frame_support; -use ::macro_magic::use_attr; #[doc(hidden)] pub use sp_tracing; From 194da7f5ca610c6e197da3f322fad2169a1282e9 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 28 Apr 2023 12:31:17 -0400 Subject: [PATCH 058/116] use explicit macro_magic::use_attr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- frame/support/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 2abfe9490b292..033212fe5073c 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -211,7 +211,7 @@ impl TypeId for PalletId { /// ``` pub use frame_support_procedural::storage_alias; -#[use_attr] +#[macro_magic::use_attr] pub use frame_support_procedural::derive_impl; /// Create new implementations of the [`Get`](crate::traits::Get) trait. From 4dd44405b44cdf4840872f1a033c3f389c966383 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 28 Apr 2023 13:25:03 -0400 Subject: [PATCH 059/116] remove unneeded {} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- frame/system/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 1a4fb999fab02..cae93d27d1608 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -207,7 +207,7 @@ pub mod pallet { use super::*; use sp_runtime::traits::IdentityLookup; - pub struct TestDefaultConfig {} + pub struct TestDefaultConfig; #[register_default_impl(TestDefaultConfig)] impl DefaultConfig for TestDefaultConfig { From e32e8a175963570c78eaa6c20f0ebddf83ff3bff Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 28 Apr 2023 13:27:43 -0400 Subject: [PATCH 060/116] remove unneeded collect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- frame/support/procedural/src/derive_impl.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 0972fbc9f94c9..ed928f790cea2 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -120,8 +120,7 @@ fn combine_impls( Some(item) } } - }) - .collect::>(); + }); final_impl.items.extend(extended_items); final_impl } From f90f13d09824d9e520674ac9e3db194694f363aa Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 28 Apr 2023 13:47:08 -0400 Subject: [PATCH 061/116] add docs for TestDefaultConfig --- frame/system/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index cae93d27d1608..b439a5a2368a5 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -207,6 +207,12 @@ pub mod pallet { use super::*; use sp_runtime::traits::IdentityLookup; + /// Provides a viable default config that can be used with + /// [`derive_impl`](`frame_support::derive_impl`) to derive a testing pallet config + /// based on this one. + /// + /// See `Test` in the "basic" example pallet's `test.rs` for an example of a + /// downstream user of this particular `TestDefaultConfig` pub struct TestDefaultConfig; #[register_default_impl(TestDefaultConfig)] From edfc83b6eebfe32e99c0422d778615f15062e9d7 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 28 Apr 2023 13:59:27 -0400 Subject: [PATCH 062/116] remove unneeded `#[export_tokens]` on `DefaultConfig` --- frame/support/procedural/src/pallet/expand/config.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index baa5ae74cdda9..23f50855ff1fb 100644 --- a/frame/support/procedural/src/pallet/expand/config.rs +++ b/frame/support/procedural/src/pallet/expand/config.rs @@ -45,13 +45,7 @@ pub fn expand_config(def: &mut Def) -> TokenStream { } if let Some(trait_items) = &config.default_sub_trait { - // get reference to frame_support - let support = match generate_crate_access_2018("frame-support") { - Ok(krate) => krate, - Err(err) => return err.to_compile_error(), - }; quote!( - #[#support::macro_magic::export_tokens] pub trait DefaultConfig { #(#trait_items)* } From efd922229425a529ba17e321318d227c0dd52cb7 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 28 Apr 2023 14:15:11 -0400 Subject: [PATCH 063/116] add docs for auto-generated `DefaultConfig` --- frame/support/procedural/src/pallet/expand/config.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index 23f50855ff1fb..83e3d7093d1c5 100644 --- a/frame/support/procedural/src/pallet/expand/config.rs +++ b/frame/support/procedural/src/pallet/expand/config.rs @@ -16,7 +16,7 @@ // limitations under the License. use crate::pallet::Def; -use frame_support_procedural_tools::{generate_crate_access_2018, get_doc_literals}; +use frame_support_procedural_tools::get_doc_literals; use proc_macro2::TokenStream; use quote::quote; use syn::{parse_quote, Item}; @@ -46,6 +46,12 @@ pub fn expand_config(def: &mut Def) -> TokenStream { if let Some(trait_items) = &config.default_sub_trait { quote!( + /// Based on [`Config`]. Auto-generated by + /// [`#[pallet::default_config]`](`frame_support::pallet_macros::default_config`). + /// Can be used in tandem with + /// [`#[register_default_config]`](`frame_support::register_default_config`) and + /// [`#[derive_impl]`](`frame_support::derive_impl`) to derive test config traits + /// based on existing pallet config traits in a safe and developer-friendly way. pub trait DefaultConfig { #(#trait_items)* } From 78ac0d5be3e3a3fbf685748fd835f0f843deab95 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 28 Apr 2023 14:29:10 -0400 Subject: [PATCH 064/116] no need to clone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- frame/support/procedural/src/derive_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index ed928f790cea2..ec430f5cb8b8d 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -51,7 +51,7 @@ impl ToTokens for DeriveImplAttrArgs { /// /// Used by [`combine_impls`] to determine whether we can compare [`ImplItem`]s by [`Ident`] /// or not. -fn impl_item_ident(impl_item: &ImplItem) -> Option { +fn impl_item_ident(impl_item: &ImplItem) -> Option<&Ident> { match impl_item { ImplItem::Const(item) => Some(item.ident.clone()), ImplItem::Fn(item) => Some(item.sig.ident.clone()), From 1dae2993471c52f3223fa38aa367e2c228e26ecb Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 28 Apr 2023 14:37:56 -0400 Subject: [PATCH 065/116] clean up combine_impls + compiling again --- frame/support/procedural/src/derive_impl.rs | 56 ++++++++++----------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index ec430f5cb8b8d..a23b3a691c68b 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -53,10 +53,10 @@ impl ToTokens for DeriveImplAttrArgs { /// or not. fn impl_item_ident(impl_item: &ImplItem) -> Option<&Ident> { match impl_item { - ImplItem::Const(item) => Some(item.ident.clone()), - ImplItem::Fn(item) => Some(item.sig.ident.clone()), - ImplItem::Type(item) => Some(item.ident.clone()), - ImplItem::Macro(item) => item.mac.path.get_ident().cloned(), + ImplItem::Const(item) => Some(&item.ident), + ImplItem::Fn(item) => Some(&item.sig.ident), + ImplItem::Type(item) => Some(&item.ident), + ImplItem::Macro(item) => item.mac.path.get_ident(), _ => None, } } @@ -83,6 +83,7 @@ fn combine_impls( .items .iter() .filter_map(|impl_item| impl_item_ident(impl_item)) + .cloned() .collect(); let existing_unsupported_items: HashSet = local_impl .items @@ -91,36 +92,33 @@ fn combine_impls( .cloned() .collect(); let mut final_impl = local_impl; - let extended_items = foreign_impl - .items - .into_iter() - .filter_map(|item| { - if let Some(ident) = impl_item_ident(&item) { - if existing_local_keys.contains(&ident) { - // do not copy colliding items that have an ident - None - } else { - if matches!(item, ImplItem::Type(_)) { - // modify and insert uncolliding type items - let modified_item: ImplItem = parse_quote! { - type #ident = <#foreign_path as #disambiguation_path>::#ident; - }; - Some(modified_item) - } else { - // copy uncolliding non-type items that have an ident - Some(item) - } - } + let extended_items = foreign_impl.items.into_iter().filter_map(|item| { + if let Some(ident) = impl_item_ident(&item) { + if existing_local_keys.contains(&ident) { + // do not copy colliding items that have an ident + None } else { - if existing_unsupported_items.contains(&item) { - // do not copy colliding items that lack an ident - None + if matches!(item, ImplItem::Type(_)) { + // modify and insert uncolliding type items + let modified_item: ImplItem = parse_quote! { + type #ident = <#foreign_path as #disambiguation_path>::#ident; + }; + Some(modified_item) } else { - // copy uncolliding items without an ident verbaitm + // copy uncolliding non-type items that have an ident Some(item) } } - }); + } else { + if existing_unsupported_items.contains(&item) { + // do not copy colliding items that lack an ident + None + } else { + // copy uncolliding items without an ident verbaitm + Some(item) + } + } + }); final_impl.items.extend(extended_items); final_impl } From faa8dcecd52179f2502fd8d70ffb4184adff4462 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 28 Apr 2023 14:58:16 -0400 Subject: [PATCH 066/116] remove unused dependency --- Cargo.lock | 1 - frame/system/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b04fab65ca7e1..8edf83368a8f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2582,7 +2582,6 @@ dependencies = [ "criterion", "frame-support", "log", - "macro_magic", "parity-scale-codec", "scale-info", "serde", diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 5e0c9e6369c29..c97eb66382ed6 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -17,7 +17,6 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } -macro_magic = "0.3.3" frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } From 8374ed8f299bff53e14ac704cfb74c359cac198c Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 28 Apr 2023 15:19:17 -0400 Subject: [PATCH 067/116] simplify struct definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- frame/support/procedural/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index d94ed739782a9..c83302caadbe7 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -1015,7 +1015,7 @@ pub fn no_default(_: TokenStream, _: TokenStream) -> TokenStream { /// ## Example /// /// ```ignore -/// pub struct ExampleTestDefaultConfig {} +/// pub struct ExampleTestDefaultConfig; /// /// #[register_default_impl(ExampleTestDefaultConfig)] /// impl DefaultConfig for ExampleTestDefaultConfig { From 8b22ea646154ab584b2aa3ba17ccf7f363788979 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 2 May 2023 13:56:09 -0400 Subject: [PATCH 068/116] fix register_default_impl docs --- frame/support/procedural/src/lib.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index c83302caadbe7..62f3a7989113a 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -1000,17 +1000,12 @@ pub fn no_default(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// Attach this attribute to an impl statement that needs to be registered for use with the -/// [`macro@derive_impl`] attribute macro. +/// Attach this attribute to an impl statement that you want to use with +/// [`#[derive_impl(..)]`](`macro@derive_impl`). /// -/// You must also specify an ident as the only argument to the attribute. This ident will be -/// used as the export name for this default config impl, and is the name you must provide to -/// [`macro@derive_impl`] when you import this impl. -/// -/// The ident you provide is exported at the root of the crate where it is defined, so the -/// ident must be unique at the crate level so as not to collide with other items. This is -/// because internally this attribute aliases to macro_magic's `#[export_tokens]` macro, which -/// relies on crate-level `macro_rules!` exports to export tokens for use elsewhere. +/// You must also provide an identifier/name as the attribute's argument. This is the name you +/// must provide to [`#[derive_impl(..)]`](`macro@derive_impl`) when you import this impl via +/// the `foreign_path` argument. This name should be unique at the crate-level. /// /// ## Example /// @@ -1027,7 +1022,6 @@ pub fn no_default(_: TokenStream, _: TokenStream) -> TokenStream { /// type MaxConsumers = frame_support::traits::ConstU32<16>; /// } /// ``` -/// /// This macro acts as a thin wrapper around macro_magic's `#[export_tokens]`. See the docs /// [here](https://docs.rs/macro_magic/latest/macro_magic/attr.export_tokens.html) for more info. #[proc_macro_attribute] From d7f3f6a5ee965ca6b35b080759d19c544f3c62f8 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 2 May 2023 14:00:01 -0400 Subject: [PATCH 069/116] reduce rightward drift / refactor Co-authored-by: Keith Yeung --- frame/support/procedural/src/derive_impl.rs | 47 +++++++++------------ 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index a23b3a691c68b..d4474ae9bf7e9 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -79,44 +79,37 @@ fn combine_impls( foreign_path: Path, disambiguation_path: Path, ) -> ItemImpl { - let existing_local_keys: HashSet = local_impl + let (existing_local_keys, existing_unsupported_items): (HashSet, HashSet) = local_impl .items .iter() - .filter_map(|impl_item| impl_item_ident(impl_item)) - .cloned() - .collect(); - let existing_unsupported_items: HashSet = local_impl - .items - .iter() - .filter(|impl_item| impl_item_ident(impl_item).is_none()) .cloned() + .filter(|impl_item| impl_item_ident(impl_item).is_some()) + .partition(); + let existing_local_keys: HashSet = existing_local_keys + .into_iter() + .filter_map(|item| impl_item_ident(item)) .collect(); let mut final_impl = local_impl; let extended_items = foreign_impl.items.into_iter().filter_map(|item| { if let Some(ident) = impl_item_ident(&item) { if existing_local_keys.contains(&ident) { // do not copy colliding items that have an ident - None - } else { - if matches!(item, ImplItem::Type(_)) { - // modify and insert uncolliding type items - let modified_item: ImplItem = parse_quote! { - type #ident = <#foreign_path as #disambiguation_path>::#ident; - }; - Some(modified_item) - } else { - // copy uncolliding non-type items that have an ident - Some(item) - } + return None } - } else { - if existing_unsupported_items.contains(&item) { - // do not copy colliding items that lack an ident - None - } else { - // copy uncolliding items without an ident verbaitm - Some(item) + if matches!(item, ImplItem::Type(_)) { + // modify and insert uncolliding type items + let modified_item: ImplItem = parse_quote! { + type #ident = <#foreign_path as #disambiguation_path>::#ident; + }; + return Some(modified_item) } + // copy uncolliding non-type items that have an ident + Some(item) + } else { + // do not copy colliding items that lack an ident + (!existing_unsupported_items.contains(&item)) + // copy uncolliding items without an ident verbatim + .then_some(item) } }); final_impl.items.extend(extended_items); From 5b905751b580a451542836c3fb365cbc687ea738 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 2 May 2023 14:21:43 -0400 Subject: [PATCH 070/116] fix derive_impl after keith's changes --- frame/support/procedural/src/derive_impl.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index d4474ae9bf7e9..7c81c834cfcc9 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -79,15 +79,15 @@ fn combine_impls( foreign_path: Path, disambiguation_path: Path, ) -> ItemImpl { - let (existing_local_keys, existing_unsupported_items): (HashSet, HashSet) = local_impl - .items - .iter() - .cloned() - .filter(|impl_item| impl_item_ident(impl_item).is_some()) - .partition(); + let (existing_local_keys, existing_unsupported_items): (HashSet, HashSet) = + local_impl + .items + .iter() + .cloned() + .partition(|impl_item| impl_item_ident(impl_item).is_some()); let existing_local_keys: HashSet = existing_local_keys .into_iter() - .filter_map(|item| impl_item_ident(item)) + .filter_map(|item| impl_item_ident(&item).cloned()) .collect(); let mut final_impl = local_impl; let extended_items = foreign_impl.items.into_iter().filter_map(|item| { From afae21c36ebd5ee5b6f63a4d8c8febaa015d5db1 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 2 May 2023 18:09:09 -0400 Subject: [PATCH 071/116] simplify disambiguation_path calculation Co-authored-by: Keith Yeung --- frame/support/procedural/src/derive_impl.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 7c81c834cfcc9..f8f00a45013c9 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -139,18 +139,15 @@ pub fn derive_impl( // have disambiguation_path default to the item being impl'd in the foreign impl if we // don't specify an `as [disambiguation_path]` in the macro attr - let disambiguation_path = match disambiguation_path { - Some(disambiguation_path) => disambiguation_path, - None => { - let Some((_, foreign_impl_path, _)) = foreign_impl.clone().trait_ else { - return Err( - syn::Error::new(foreign_impl.span(), - "Impl statement must have a defined type being implemented for a defined type such as `impl A for B`") - ); - }; - foreign_impl_path - }, - }; + let disambiguation_path = disambiguation_path.unwrap_or_else(|| { + let Some((_, foreign_impl_path, _)) = foreign_impl.clone().trait_ else { + return Err( + syn::Error::new(foreign_impl.span(), + "Impl statement must have a defined type being implemented for a defined type such as `impl A for B`") + ); + }; + Ok(foreign_impl_path) + })?; // generate the combined impl let combined_impl = combine_impls(local_impl, foreign_impl, foreign_path, disambiguation_path); From f784efc9145a0aff63915782404f7f9938f85755 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 2 May 2023 23:25:22 -0400 Subject: [PATCH 072/116] compiling again --- frame/support/procedural/src/derive_impl.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index f8f00a45013c9..28bc97afec913 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -139,15 +139,14 @@ pub fn derive_impl( // have disambiguation_path default to the item being impl'd in the foreign impl if we // don't specify an `as [disambiguation_path]` in the macro attr - let disambiguation_path = disambiguation_path.unwrap_or_else(|| { - let Some((_, foreign_impl_path, _)) = foreign_impl.clone().trait_ else { - return Err( - syn::Error::new(foreign_impl.span(), - "Impl statement must have a defined type being implemented for a defined type such as `impl A for B`") - ); - }; - Ok(foreign_impl_path) - })?; + let disambiguation_path = match (disambiguation_path, foreign_impl.clone().trait_) { + (Some(disambiguation_path), _) => disambiguation_path, + (None, Some((_, foreign_impl_path, _))) => foreign_impl_path, + _ => return Err(syn::Error::new( + foreign_impl.span(), + "Impl statement must have a defined type being implemented for a defined type such as `impl A for B`" + )) + }; // generate the combined impl let combined_impl = combine_impls(local_impl, foreign_impl, foreign_path, disambiguation_path); From 763a93aadaad755bda495a7f9f53b2a1d62be261 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 2 May 2023 23:43:01 -0400 Subject: [PATCH 073/116] simplify parsing of trait item Co-authored-by: Keith Yeung --- .../procedural/src/pallet/parse/config.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 8e0ac3de050bd..451b3cb3cb0a0 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -342,17 +342,13 @@ impl ConfigDef { helper::take_first_item_pallet_attr::(trait_item) { if pallet_attr.ident == "constant" { - match trait_item { - syn::TraitItem::Type(ref typ) => { - let constant = ConstMetadataDef::try_from(typ)?; - consts_metadata.push(constant); - }, - _ => { - let msg = - "Invalid pallet::constant in pallet::config, expected type trait item"; - return Err(syn::Error::new(trait_item.span(), msg)) - }, - } + let syn::TraitItem::Type(ref typ) = trait_item else { + let msg = + "Invalid pallet::constant in pallet::config, expected type trait item"; + return Err(syn::Error::new(trait_item.span(), msg)) + }; + let constant = ConstMetadataDef::try_from(typ)?; + consts_metadata.push(constant); } else if pallet_attr.ident == "no_default" { no_default = true } else { From 16b4d5aacdf86c140ce4edb1f7247cd6651e8a4e Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 2 May 2023 23:50:17 -0400 Subject: [PATCH 074/116] rename preludes => prelude Co-authored-by: Keith Yeung --- frame/system/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index b439a5a2368a5..9d62ffa06eac3 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -200,7 +200,7 @@ pub mod pallet { use crate::{self as frame_system, pallet_prelude::*, *}; use frame_support::pallet_prelude::*; - pub mod preludes { + pub mod prelude { use super::*; pub mod testing { type AccountId = u64; From bc688f999cdb4062c249ca292ddd4274ef17a138 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 3 May 2023 00:05:11 -0400 Subject: [PATCH 075/116] fix other places where we used preludes instead of prelude --- frame/examples/basic/src/tests.rs | 2 +- frame/support/procedural/src/derive_impl.rs | 2 +- frame/support/procedural/src/lib.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index e33c8007f61a5..a069a229f1f16 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -50,7 +50,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::preludes::testing::TestDefaultConfig as frame_system::pallet::DefaultConfig)] +#[derive_impl(frame_system::prelude::testing::TestDefaultConfig as frame_system::pallet::DefaultConfig)] impl frame_system::Config for Test { // These are all defined by system as mandatory. type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 28bc97afec913..902eeb76d3f7d 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -161,7 +161,7 @@ fn test_derive_impl_attr_args_parsing() { )) .unwrap(); parse2::(quote!( - frame_system::preludes::testing::TestDefaultConfig as DefaultConfig + frame_system::prelude::testing::TestDefaultConfig as DefaultConfig )) .unwrap(); parse2::(quote!(Something as some::path::DefaultConfig)).unwrap(); diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 62f3a7989113a..4c9f25d27d08d 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -874,7 +874,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// Consider the following taken from the `basic` example pallet: /// /// ```ignore -/// #[derive_impl(frame_system::preludes::testing::TestDefaultConfig as frame_system::pallet::DefaultConfig)] +/// #[derive_impl(frame_system::prelude::testing::TestDefaultConfig as frame_system::pallet::DefaultConfig)] /// impl frame_system::Config for Test { /// // These are all defined by system as mandatory. /// type BaseCallFilter = frame_support::traits::Everything; @@ -920,7 +920,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// /// ```ignore /// impl frame_system::Config for Test { -/// use frame_system::preludes::testing::TestDefaultConfig; +/// use frame_system::prelude::testing::TestDefaultConfig; /// use frame_system::pallet::DefaultConfig; /// /// type BaseCallFilter = frame_support::traits::Everything; From 8077b7b21b75a854daed014456bce48e6002b899 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 3 May 2023 08:25:43 -0400 Subject: [PATCH 076/116] fix indents --- frame/support/procedural/src/derive_impl.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 902eeb76d3f7d..1f6420606afb9 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -142,10 +142,12 @@ pub fn derive_impl( let disambiguation_path = match (disambiguation_path, foreign_impl.clone().trait_) { (Some(disambiguation_path), _) => disambiguation_path, (None, Some((_, foreign_impl_path, _))) => foreign_impl_path, - _ => return Err(syn::Error::new( + _ => + return Err(syn::Error::new( foreign_impl.span(), - "Impl statement must have a defined type being implemented for a defined type such as `impl A for B`" - )) + "Impl statement must have a defined type being implemented \ + for a defined type such as `impl A for B`", + )), }; // generate the combined impl From a399ecd48b9eacaccc2a2afd365762c8123402e9 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 3 May 2023 09:46:12 -0400 Subject: [PATCH 077/116] simplify PalletAttr parsing Co-authored-by: Keith Yeung --- frame/support/procedural/src/pallet/parse/config.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 451b3cb3cb0a0..8bc26be486980 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -136,8 +136,7 @@ pub struct PalletAttr { _bracket: token::Bracket, #[inside(_bracket)] _pallet: keyword::pallet, - #[inside(_bracket)] - _sep: Token![::], + #[prefix(Token![::] in _bracket)] #[inside(_bracket)] ident: Ident, } From c825367df9e17dd1d7a4aad656a7d032ae85d311 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 3 May 2023 11:54:03 -0400 Subject: [PATCH 078/116] go back to having no_default and constant as keywords --- .../procedural/src/pallet/parse/config.rs | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 8bc26be486980..bd4cfa86c6d67 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -18,7 +18,7 @@ use super::helper; use frame_support_procedural_tools::get_doc_literals; use quote::ToTokens; -use syn::{spanned::Spanned, token, Ident, Token}; +use syn::{spanned::Spanned, token, Token}; /// List of additional token to be used for parsing. mod keyword { @@ -33,6 +33,8 @@ mod keyword { syn::custom_keyword!(Event); syn::custom_keyword!(frame_system); syn::custom_keyword!(disable_frame_system_supertrait_check); + syn::custom_keyword!(no_default); + syn::custom_keyword!(constant); } /// Input definition for the pallet config. @@ -128,6 +130,15 @@ impl syn::parse::Parse for DisableFrameSystemSupertraitCheck { } } +/// Parsing for the `typ` portion of `PalletAttr` +#[derive(derive_syn_parse::Parse, PartialEq, Eq)] +pub enum PalletAttrType { + #[peek(keyword::no_default, name = "no_default")] + NoDefault(keyword::no_default), + #[peek(keyword::constant, name = "constant")] + Constant(keyword::constant), +} + /// Parsing for `#[pallet::X]` #[derive(derive_syn_parse::Parse)] pub struct PalletAttr { @@ -138,7 +149,7 @@ pub struct PalletAttr { _pallet: keyword::pallet, #[prefix(Token![::] in _bracket)] #[inside(_bracket)] - ident: Ident, + typ: PalletAttrType, } pub struct ConfigBoundParse(syn::Ident); @@ -340,24 +351,16 @@ impl ConfigDef { if let Ok(Some(pallet_attr)) = helper::take_first_item_pallet_attr::(trait_item) { - if pallet_attr.ident == "constant" { - let syn::TraitItem::Type(ref typ) = trait_item else { - let msg = - "Invalid pallet::constant in pallet::config, expected type trait item"; - return Err(syn::Error::new(trait_item.span(), msg)) - }; - let constant = ConstMetadataDef::try_from(typ)?; - consts_metadata.push(constant); - } else if pallet_attr.ident == "no_default" { - no_default = true - } else { - return Err(syn::Error::new( - pallet_attr.ident.span(), - format!( - "Unsupported attribute `#[pallet::{}]` attached to a pallet config item", - pallet_attr.ident.to_string() - ), - )) + match (pallet_attr.typ, &trait_item) { + (PalletAttrType::Constant(_), syn::TraitItem::Type(ref typ)) => + consts_metadata.push(ConstMetadataDef::try_from(typ)?), + (PalletAttrType::Constant(_), _) => + return Err(syn::Error::new( + trait_item.span(), + "Invalid pallet::constant in pallet::config, expected \ + type trait item", + )), + (PalletAttrType::NoDefault(_), _) => no_default = true, } } } From b373b52f999cae063a9ba77c986aa0714fe7be68 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 3 May 2023 12:35:06 -0400 Subject: [PATCH 079/116] make it more clear that disambiguation_path is optional --- frame/support/procedural/src/lib.rs | 35 +++++++++++++++++------------ 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 4c9f25d27d08d..a0a32907dbe50 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -790,7 +790,19 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// The attribute should be attached to an impl block (strictly speaking a `syn::ItemImpl`) for /// which we want to inject defaults in the event of missing trait items in the block. /// -/// The attribute takes two arguments separated by an `as` with the general form: +/// The attribute minimally takes a single `foreign_path` argument, which should be the module +/// path to an impl registered via [`#[register_default_impl]`](`macro@register_default_impl`) +/// that contains the default trait items we want to potentially inject, with the general form: +/// +/// ```ignore +/// #[derive_impl(foreign_path)] +/// impl SomeTrait for SomeStruct { +/// ... +/// } +/// ``` +/// +/// Optionally, a `disambiguation_path` can be specified as follows by providing `as +/// path::here` after the `foreign_path`: /// /// ```ignore /// #[derive_impl(foreign_path as disambiguation_path)] @@ -799,20 +811,15 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// } /// ``` /// -/// The `foreign_path` should be the path to an impl registered via -/// [`#[register_default_impl]`](`macro@register_default_impl`) that contains the default trait -/// items we want to potentially inject. -/// -/// The `disambiguation_path` should be the path to a trait that will be used to qualify all -/// default entries that are injected into the local impl. For example if your `foreign_path` -/// is `some::path::TestTrait` and your `disambiguation_path` is `another::path::DefaultTrait`, -/// any items injected into the local impl will be qualified as `::specific_trait_item`. +/// The `disambiguation_path`, if specified, should be the path to a trait that will be used to +/// qualify all default entries that are injected into the local impl. For example if your +/// `foreign_path` is `some::path::TestTrait` and your `disambiguation_path` is +/// `another::path::DefaultTrait`, any items injected into the local impl will be qualified as +/// `::specific_trait_item`. /// -/// Optionally, you may omit the `as disambiguation_path` portion, in which case the -/// `disambiguation_path` will internally default to `A` from the `impl A for B` part of the -/// foreign impl. This is useful for scenarios where all of the relevant types are already in -/// scope. +/// If you omit the `as disambiguation_path` portion, the `disambiguation_path` will internally +/// default to `A` from the `impl A for B` part of the foreign impl. This is useful for +/// scenarios where all of the relevant types are already in scope via `use` statements. /// /// Conversely, the `foreign_path` argument is required and cannot be omitted. /// From af16dacb4b39adc8bbf6c6f4eb5c8783d5d1b3fc Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 3 May 2023 21:15:12 -0400 Subject: [PATCH 080/116] make default_trait_items just a Vec instead of Option --- .../procedural/src/pallet/expand/config.rs | 5 ++++- .../procedural/src/pallet/parse/config.rs | 16 ++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index 83e3d7093d1c5..3a5f8efe929db 100644 --- a/frame/support/procedural/src/pallet/expand/config.rs +++ b/frame/support/procedural/src/pallet/expand/config.rs @@ -44,7 +44,10 @@ pub fn expand_config(def: &mut Def) -> TokenStream { )); } - if let Some(trait_items) = &config.default_sub_trait { + // we only emit `DefaultConfig` if there are trait items, so an empty `DefaultConfig` is + // impossible consequently + if config.default_sub_trait.len() > 0 { + let trait_items = &config.default_sub_trait; quote!( /// Based on [`Config`]. Auto-generated by /// [`#[pallet::default_config]`](`frame_support::pallet_macros::default_config`). diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index bd4cfa86c6d67..b4afea1e1d9c9 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -56,9 +56,10 @@ pub struct ConfigDef { pub attr_span: proc_macro2::Span, /// Whether a default sub-trait should be generated. /// - /// No, if `None`. - /// Yes, if `Some(_)`, with the inner items that should be included. - pub default_sub_trait: Option>, + /// Contains default sub-trait items (instantiated by `#[pallet::default_config]`). Vec + /// will be empty if `#[pallet::default_config]` is not specified or if there are no trait + /// items + pub default_sub_trait: Vec, } /// Input definition for a constant in pallet config. @@ -340,7 +341,7 @@ impl ConfigDef { let mut has_event_type = false; let mut consts_metadata = vec![]; - let mut default_subtrait_items = vec![]; + let mut default_sub_trait = vec![]; for trait_item in &mut item.items { // Parse for event let is_event = check_event_type(frame_system, trait_item, has_instance)?; @@ -366,15 +367,10 @@ impl ConfigDef { } if !no_default && !is_event && enable_default { - default_subtrait_items.push(trait_item.clone()); + default_sub_trait.push(trait_item.clone()); } } - let default_sub_trait = match enable_default { - true => Some(default_subtrait_items), - false => None, - }; - let attr: Option = helper::take_first_item_pallet_attr(&mut item.attrs)?; let disable_system_supertrait_check = attr.is_some(); From ce06d171e281b376be37853f7cf0a87321792d5f Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 3 May 2023 22:06:59 -0400 Subject: [PATCH 081/116] rename foreign_path => default_impl_path within substrate --- frame/support/procedural/src/derive_impl.rs | 23 ++++++++++--------- frame/support/procedural/src/lib.rs | 21 +++++++++-------- ...reign_path.rs => bad_default_impl_path.rs} | 0 ...th.stderr => bad_default_impl_path.stderr} | 2 +- 4 files changed, 24 insertions(+), 22 deletions(-) rename frame/support/test/tests/derive_impl_ui/{bad_foreign_path.rs => bad_default_impl_path.rs} (100%) rename frame/support/test/tests/derive_impl_ui/{bad_foreign_path.stderr => bad_default_impl_path.stderr} (84%) diff --git a/frame/support/procedural/src/derive_impl.rs b/frame/support/procedural/src/derive_impl.rs index 1f6420606afb9..5ea44c35bb646 100644 --- a/frame/support/procedural/src/derive_impl.rs +++ b/frame/support/procedural/src/derive_impl.rs @@ -26,7 +26,7 @@ use syn::{parse2, parse_quote, spanned::Spanned, Ident, ImplItem, ItemImpl, Path #[derive(Parse)] pub struct DeriveImplAttrArgs { - pub foreign_path: Path, + pub default_impl_path: Path, _as: Option, #[parse_if(_as.is_some())] pub disambiguation_path: Option, @@ -34,13 +34,13 @@ pub struct DeriveImplAttrArgs { impl ForeignPath for DeriveImplAttrArgs { fn foreign_path(&self) -> &Path { - &self.foreign_path + &self.default_impl_path } } impl ToTokens for DeriveImplAttrArgs { fn to_tokens(&self, tokens: &mut TokenStream2) { - tokens.extend(self.foreign_path.to_token_stream()); + tokens.extend(self.default_impl_path.to_token_stream()); tokens.extend(self._as.to_token_stream()); tokens.extend(self.disambiguation_path.to_token_stream()); } @@ -69,14 +69,14 @@ fn impl_item_ident(impl_item: &ImplItem) -> Option<&Ident> { /// This process has the following caveats: /// * Colliding items that have an ident are not copied into `local_impl` /// * Uncolliding items that have an ident are copied into `local_impl` but are qualified as `type -/// #ident = <#foreign_path as #disambiguation_path>::#ident;` +/// #ident = <#default_impl_path as #disambiguation_path>::#ident;` /// * Items that lack an ident are de-duplicated so only unique items that lack an ident are copied /// into `local_impl`. Items that lack an ident and also exist verbatim in `local_impl` are not /// copied over. fn combine_impls( local_impl: ItemImpl, foreign_impl: ItemImpl, - foreign_path: Path, + default_impl_path: Path, disambiguation_path: Path, ) -> ItemImpl { let (existing_local_keys, existing_unsupported_items): (HashSet, HashSet) = @@ -99,7 +99,7 @@ fn combine_impls( if matches!(item, ImplItem::Type(_)) { // modify and insert uncolliding type items let modified_item: ImplItem = parse_quote! { - type #ident = <#foreign_path as #disambiguation_path>::#ident; + type #ident = <#default_impl_path as #disambiguation_path>::#ident; }; return Some(modified_item) } @@ -118,8 +118,8 @@ fn combine_impls( /// Internal implementation behind [`#[derive_impl(..)]`](`macro@crate::derive_impl`). /// -/// `foreign_path`: the module path of the external `impl` statement whose tokens we are -/// importing via `macro_magic` +/// `default_impl_path`: the module path of the external `impl` statement whose tokens we are +/// importing via `macro_magic` /// /// `foreign_tokens`: the tokens for the external `impl` statement /// @@ -128,14 +128,14 @@ fn combine_impls( /// `disambiguation_path`: the module path of the external trait we will use to qualify /// defaults imported from the external `impl` statement pub fn derive_impl( - foreign_path: TokenStream2, + default_impl_path: TokenStream2, foreign_tokens: TokenStream2, local_tokens: TokenStream2, disambiguation_path: Option, ) -> Result { let local_impl = parse2::(local_tokens)?; let foreign_impl = parse2::(foreign_tokens)?; - let foreign_path = parse2::(foreign_path)?; + let default_impl_path = parse2::(default_impl_path)?; // have disambiguation_path default to the item being impl'd in the foreign impl if we // don't specify an `as [disambiguation_path]` in the macro attr @@ -151,7 +151,8 @@ pub fn derive_impl( }; // generate the combined impl - let combined_impl = combine_impls(local_impl, foreign_impl, foreign_path, disambiguation_path); + let combined_impl = + combine_impls(local_impl, foreign_impl, default_impl_path, disambiguation_path); Ok(quote!(#combined_impl)) } diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index a0a32907dbe50..6d0045c3eefe3 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -790,22 +790,23 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// The attribute should be attached to an impl block (strictly speaking a `syn::ItemImpl`) for /// which we want to inject defaults in the event of missing trait items in the block. /// -/// The attribute minimally takes a single `foreign_path` argument, which should be the module -/// path to an impl registered via [`#[register_default_impl]`](`macro@register_default_impl`) -/// that contains the default trait items we want to potentially inject, with the general form: +/// The attribute minimally takes a single `default_impl_path` argument, which should be the +/// module path to an impl registered via +/// [`#[register_default_impl]`](`macro@register_default_impl`) that contains the default trait +/// items we want to potentially inject, with the general form: /// /// ```ignore -/// #[derive_impl(foreign_path)] +/// #[derive_impl(default_impl_path)] /// impl SomeTrait for SomeStruct { /// ... /// } /// ``` /// /// Optionally, a `disambiguation_path` can be specified as follows by providing `as -/// path::here` after the `foreign_path`: +/// path::here` after the `default_impl_path`: /// /// ```ignore -/// #[derive_impl(foreign_path as disambiguation_path)] +/// #[derive_impl(default_impl_path as disambiguation_path)] /// impl SomeTrait for SomeStruct { /// ... /// } @@ -813,7 +814,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// /// The `disambiguation_path`, if specified, should be the path to a trait that will be used to /// qualify all default entries that are injected into the local impl. For example if your -/// `foreign_path` is `some::path::TestTrait` and your `disambiguation_path` is +/// `default_impl_path` is `some::path::TestTrait` and your `disambiguation_path` is /// `another::path::DefaultTrait`, any items injected into the local impl will be qualified as /// `::specific_trait_item`. /// @@ -821,7 +822,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// default to `A` from the `impl A for B` part of the foreign impl. This is useful for /// scenarios where all of the relevant types are already in scope via `use` statements. /// -/// Conversely, the `foreign_path` argument is required and cannot be omitted. +/// Conversely, the `default_impl_path` argument is required and cannot be omitted. /// /// You can also make use of `#[pallet::no_default]` on specific items in your foreign trait /// that you want to ensure will not be copied over but that you nonetheless want to use @@ -852,7 +853,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// /// ## Expansion /// -/// The `#[derive_impl(foreign_path as disambiguation_path)]` attribute will expand to the +/// The `#[derive_impl(default_impl_path as disambiguation_path)]` attribute will expand to the /// local impl, with any extra items from the foreign impl that aren't present in the local /// impl also included. In the case of a colliding trait item, the version of the item that /// exists in the local impl will be retained. All imported items are qualified by the @@ -1012,7 +1013,7 @@ pub fn no_default(_: TokenStream, _: TokenStream) -> TokenStream { /// /// You must also provide an identifier/name as the attribute's argument. This is the name you /// must provide to [`#[derive_impl(..)]`](`macro@derive_impl`) when you import this impl via -/// the `foreign_path` argument. This name should be unique at the crate-level. +/// the `default_impl_path` argument. This name should be unique at the crate-level. /// /// ## Example /// diff --git a/frame/support/test/tests/derive_impl_ui/bad_foreign_path.rs b/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.rs similarity index 100% rename from frame/support/test/tests/derive_impl_ui/bad_foreign_path.rs rename to frame/support/test/tests/derive_impl_ui/bad_default_impl_path.rs diff --git a/frame/support/test/tests/derive_impl_ui/bad_foreign_path.stderr b/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.stderr similarity index 84% rename from frame/support/test/tests/derive_impl_ui/bad_foreign_path.stderr rename to frame/support/test/tests/derive_impl_ui/bad_default_impl_path.stderr index d1e348e15faf4..1cac166246276 100644 --- a/frame/support/test/tests/derive_impl_ui/bad_foreign_path.stderr +++ b/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.stderr @@ -1,5 +1,5 @@ error: cannot find macro `__export_tokens_tt_tiger` in this scope - --> tests/derive_impl_ui/bad_foreign_path.rs:42:1 + --> tests/derive_impl_ui/bad_default_impl_path.rs:42:1 | 42 | #[derive_impl(Tiger as Animal)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From e7c9056a6ff67bb7a8c123de08a382893edf35d7 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 3 May 2023 22:34:11 -0400 Subject: [PATCH 082/116] fix docs --- frame/support/procedural/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 6d0045c3eefe3..d4bc0c4ecba58 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -819,15 +819,15 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// `::specific_trait_item`. /// /// If you omit the `as disambiguation_path` portion, the `disambiguation_path` will internally -/// default to `A` from the `impl A for B` part of the foreign impl. This is useful for +/// default to `A` from the `impl A for B` part of the default impl. This is useful for /// scenarios where all of the relevant types are already in scope via `use` statements. /// /// Conversely, the `default_impl_path` argument is required and cannot be omitted. /// -/// You can also make use of `#[pallet::no_default]` on specific items in your foreign trait +/// You can also make use of `#[pallet::no_default]` on specific items in your default impl /// that you want to ensure will not be copied over but that you nonetheless want to use -/// locally in the context of the foreign trait and the pallet (or context) in which it is -/// defined +/// locally in the context of the foreign impl and the pallet (or context) in which it is +/// defined. /// /// ## Importing & Re-Exporting /// From 655657eb4897e3821ce4e7b7d3ca5e140dbfdeb5 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 3 May 2023 22:47:41 -0400 Subject: [PATCH 083/116] Change {} to ; MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- frame/support/procedural/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index d4bc0c4ecba58..7e2d03ad9bf8c 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -900,7 +900,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// where `TestDefaultConfig` was defined and registered as follows: /// /// ```ignore -/// pub struct TestDefaultConfig {} +/// pub struct TestDefaultConfig; /// /// #[register_default_impl(TestDefaultConfig)] /// impl DefaultConfig for TestDefaultConfig { From 9bcf5e86a95f1645c42c62bb8f9158209f009b2f Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 3 May 2023 23:09:45 -0400 Subject: [PATCH 084/116] highlight full end-to-end example with link --- frame/support/procedural/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 7e2d03ad9bf8c..7c6a731b6466f 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -785,6 +785,8 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// partial impl and an external impl containing defaults that can be overriden in the local /// impl. /// +/// For a full end-to-end example, see [below](#use-case-auto-derive-test-pallet-config-traits). +/// /// ## Usage /// /// The attribute should be attached to an impl block (strictly speaking a `syn::ItemImpl`) for From 4449600067b0c545c1dc5db313c13d71a6f0cdfe Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 11 May 2023 23:04:40 -0400 Subject: [PATCH 085/116] add pallet-default-config-example, start by copying dev mode code --- Cargo.lock | 16 +++ Cargo.toml | 1 + frame/examples/default-config/Cargo.toml | 42 +++++++ frame/examples/default-config/README.md | 10 ++ frame/examples/default-config/src/lib.rs | 118 +++++++++++++++++++ frame/examples/default-config/src/tests.rs | 130 +++++++++++++++++++++ 6 files changed, 317 insertions(+) create mode 100644 frame/examples/default-config/Cargo.toml create mode 100644 frame/examples/default-config/README.md create mode 100644 frame/examples/default-config/src/lib.rs create mode 100644 frame/examples/default-config/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 8edf83368a8f4..c682e5c218ebc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6050,6 +6050,22 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-default-config-example" +version = "4.0.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "log", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-democracy" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 82e2264a3a2c6..3be9588edb8c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -107,6 +107,7 @@ members = [ "frame/examples/basic", "frame/examples/offchain-worker", "frame/examples/dev-mode", + "frame/examples/default-config", "frame/executive", "frame/nis", "frame/grandpa", diff --git a/frame/examples/default-config/Cargo.toml b/frame/examples/default-config/Cargo.toml new file mode 100644 index 0000000000000..80c0134598474 --- /dev/null +++ b/frame/examples/default-config/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "pallet-default-config-example" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "MIT-0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME example pallet demonstrating derive_impl / default_config in action" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } +pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } +sp-io = { version = "7.0.0", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } + +[dev-dependencies] +sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-balances/std", + "scale-info/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/examples/default-config/README.md b/frame/examples/default-config/README.md new file mode 100644 index 0000000000000..232de1af3f7b8 --- /dev/null +++ b/frame/examples/default-config/README.md @@ -0,0 +1,10 @@ +# Default Config Example Pallet + +An example pallet demonstrating the ability to derive default testing configs via the +`derive_impl` and `#[pallet::default_config]` macros. + +Run `cargo doc --package pallet-default-config-example --open` to view this pallet's documentation. + +**Default testing configs are not meant to be used in production** + +License: MIT-0 diff --git a/frame/examples/default-config/src/lib.rs b/frame/examples/default-config/src/lib.rs new file mode 100644 index 0000000000000..61d1bbbb03543 --- /dev/null +++ b/frame/examples/default-config/src/lib.rs @@ -0,0 +1,118 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! +//! # Dev Mode Example Pallet +//! +//! A simple example of a FRAME pallet demonstrating +//! the ease of requirements for a pallet in dev mode. +//! +//! Run `cargo doc --package pallet-dev-mode --open` to view this pallet's documentation. +//! +//! **Default test configs are not meant to be used in production** + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::dispatch::DispatchResult; +use frame_system::ensure_signed; + +// Re-export pallet items so that they can be accessed from the crate namespace. +pub use pallet::*; + +#[cfg(test)] +mod tests; + +/// A type alias for the balance type from this pallet's point of view. +type BalanceOf = ::Balance; + +/// Enable `dev_mode` for this pallet. +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: pallet_balances::Config + frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + // Simple declaration of the `Pallet` type. It is placeholder we use to implement traits and + // method. + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + /// No need to define a `weight` attribute here because of `dev_mode`. + pub fn add_dummy(origin: OriginFor, id: T::AccountId) -> DispatchResult { + ensure_root(origin)?; + + if let Some(mut dummies) = Dummy::::get() { + dummies.push(id.clone()); + Dummy::::set(Some(dummies)); + } else { + Dummy::::set(Some(vec![id.clone()])); + } + + // Let's deposit an event to let the outside world know this happened. + Self::deposit_event(Event::AddDummy { account: id }); + + Ok(()) + } + + #[pallet::call_index(1)] + /// No need to define a `weight` attribute here because of `dev_mode`. + pub fn set_bar( + origin: OriginFor, + #[pallet::compact] new_value: T::Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + // Put the new value into storage. + >::insert(&sender, new_value); + + Self::deposit_event(Event::SetBar { account: sender, balance: new_value }); + + Ok(()) + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + AddDummy { account: T::AccountId }, + SetBar { account: T::AccountId, balance: BalanceOf }, + } + + /// The MEL requirement for bounded pallets is skipped by `dev_mode`. + /// This means that all storages are marked as unbounded. + /// This is equivalent to specifying `#[pallet::unbounded]` on this type definitions. + /// When the dev_mode is removed, we would need to implement implement `MaxEncodedLen`. + #[pallet::storage] + pub type Dummy = StorageValue<_, Vec>; + + /// The Hasher requirement is skipped by `dev_mode`. So, second parameter can be `_` + /// and `Blake2_128Concat` is used as a default. + /// When the dev_mode is removed, we would need to specify the hasher like so: + /// `pub type Bar = StorageMap<_, Blake2_128Concat, T::AccountId, T::Balance>;`. + #[pallet::storage] + pub type Bar = StorageMap<_, _, T::AccountId, T::Balance>; +} diff --git a/frame/examples/default-config/src/tests.rs b/frame/examples/default-config/src/tests.rs new file mode 100644 index 0000000000000..e2f06ddda6cd7 --- /dev/null +++ b/frame/examples/default-config/src/tests.rs @@ -0,0 +1,130 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for pallet-dev-mode. + +use crate::*; +use frame_support::{assert_ok, traits::ConstU64}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, +}; +// Reexport crate as its pallet name for construct_runtime. +use crate as pallet_dev_mode; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +// For testing the pallet, we construct a mock runtime. +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Example: pallet_dev_mode::{Pallet, Call, Storage, Event}, + } +); + +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type RuntimeCall = RuntimeCall; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = u64; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; +} + +// This function basically just builds a genesis storage key/value store according to +// our desired mockup. +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = GenesisConfig { + // We use default for brevity, but you can configure as desired if needed. + system: Default::default(), + balances: Default::default(), + } + .build_storage() + .unwrap(); + t.into() +} + +#[test] +fn it_works_for_optional_value() { + new_test_ext().execute_with(|| { + assert_eq!(Dummy::::get(), None); + + let val1 = 42; + assert_ok!(Example::add_dummy(RuntimeOrigin::root(), val1)); + assert_eq!(Dummy::::get(), Some(vec![val1])); + + // Check that accumulate works when we have Some value in Dummy already. + let val2 = 27; + assert_ok!(Example::add_dummy(RuntimeOrigin::root(), val2)); + assert_eq!(Dummy::::get(), Some(vec![val1, val2])); + }); +} + +#[test] +fn set_dummy_works() { + new_test_ext().execute_with(|| { + let test_val = 133; + assert_ok!(Example::set_bar(RuntimeOrigin::signed(1), test_val.into())); + assert_eq!(Bar::::get(1), Some(test_val)); + }); +} From 238dc9c6b767cb56b604fe63d297dd0d4e566f68 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 17 May 2023 12:51:55 -0400 Subject: [PATCH 086/116] update dev-mode specific docs --- frame/examples/default-config/README.md | 2 -- frame/examples/default-config/src/lib.rs | 21 +++++---------------- frame/examples/default-config/src/tests.rs | 6 +++--- 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/frame/examples/default-config/README.md b/frame/examples/default-config/README.md index 232de1af3f7b8..068198b24b430 100644 --- a/frame/examples/default-config/README.md +++ b/frame/examples/default-config/README.md @@ -5,6 +5,4 @@ An example pallet demonstrating the ability to derive default testing configs vi Run `cargo doc --package pallet-default-config-example --open` to view this pallet's documentation. -**Default testing configs are not meant to be used in production** - License: MIT-0 diff --git a/frame/examples/default-config/src/lib.rs b/frame/examples/default-config/src/lib.rs index 61d1bbbb03543..48a8ac2e0e6fa 100644 --- a/frame/examples/default-config/src/lib.rs +++ b/frame/examples/default-config/src/lib.rs @@ -16,16 +16,16 @@ // limitations under the License. //! -//! # Dev Mode Example Pallet +//! # Default Config Pallet Example //! -//! A simple example of a FRAME pallet demonstrating -//! the ease of requirements for a pallet in dev mode. +//! A simple example of a FRAME pallet that utilizes `derive_impl` to implement a `DefaultConfig`. //! -//! Run `cargo doc --package pallet-dev-mode --open` to view this pallet's documentation. +//! Run `cargo doc --package pallet-default-config-example --open` to view this pallet's +//! documentation. //! //! **Default test configs are not meant to be used in production** -// Ensure we're `no_std` when compiling for Wasm. +// Ensure we're `no_std` when compiling for WASM. #![cfg_attr(not(feature = "std"), no_std)] use frame_support::dispatch::DispatchResult; @@ -40,7 +40,6 @@ mod tests; /// A type alias for the balance type from this pallet's point of view. type BalanceOf = ::Balance; -/// Enable `dev_mode` for this pallet. #[frame_support::pallet(dev_mode)] pub mod pallet { use super::*; @@ -61,7 +60,6 @@ pub mod pallet { #[pallet::call] impl Pallet { #[pallet::call_index(0)] - /// No need to define a `weight` attribute here because of `dev_mode`. pub fn add_dummy(origin: OriginFor, id: T::AccountId) -> DispatchResult { ensure_root(origin)?; @@ -79,7 +77,6 @@ pub mod pallet { } #[pallet::call_index(1)] - /// No need to define a `weight` attribute here because of `dev_mode`. pub fn set_bar( origin: OriginFor, #[pallet::compact] new_value: T::Balance, @@ -102,17 +99,9 @@ pub mod pallet { SetBar { account: T::AccountId, balance: BalanceOf }, } - /// The MEL requirement for bounded pallets is skipped by `dev_mode`. - /// This means that all storages are marked as unbounded. - /// This is equivalent to specifying `#[pallet::unbounded]` on this type definitions. - /// When the dev_mode is removed, we would need to implement implement `MaxEncodedLen`. #[pallet::storage] pub type Dummy = StorageValue<_, Vec>; - /// The Hasher requirement is skipped by `dev_mode`. So, second parameter can be `_` - /// and `Blake2_128Concat` is used as a default. - /// When the dev_mode is removed, we would need to specify the hasher like so: - /// `pub type Bar = StorageMap<_, Blake2_128Concat, T::AccountId, T::Balance>;`. #[pallet::storage] pub type Bar = StorageMap<_, _, T::AccountId, T::Balance>; } diff --git a/frame/examples/default-config/src/tests.rs b/frame/examples/default-config/src/tests.rs index e2f06ddda6cd7..e337c4bfe3393 100644 --- a/frame/examples/default-config/src/tests.rs +++ b/frame/examples/default-config/src/tests.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Tests for pallet-dev-mode. +//! Tests for pallet-default-config-example. use crate::*; use frame_support::{assert_ok, traits::ConstU64}; @@ -26,7 +26,7 @@ use sp_runtime::{ BuildStorage, }; // Reexport crate as its pallet name for construct_runtime. -use crate as pallet_dev_mode; +use crate as pallet_default_config_example; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -40,7 +40,7 @@ frame_support::construct_runtime!( { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Example: pallet_dev_mode::{Pallet, Call, Storage, Event}, + Example: pallet_default_config_example::{Pallet, Call, Storage, Event}, } ); From 7a7f74edb9b3f6b792a42c1c2e1400b694c4f628 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 17 May 2023 13:06:23 -0400 Subject: [PATCH 087/116] use Person and Points instead of Dummy and Bar --- frame/examples/default-config/src/lib.rs | 24 +++++++++++----------- frame/examples/default-config/src/tests.rs | 18 ++++++++-------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/frame/examples/default-config/src/lib.rs b/frame/examples/default-config/src/lib.rs index 48a8ac2e0e6fa..2b4f9313eeae9 100644 --- a/frame/examples/default-config/src/lib.rs +++ b/frame/examples/default-config/src/lib.rs @@ -60,33 +60,33 @@ pub mod pallet { #[pallet::call] impl Pallet { #[pallet::call_index(0)] - pub fn add_dummy(origin: OriginFor, id: T::AccountId) -> DispatchResult { + pub fn add_person(origin: OriginFor, id: T::AccountId) -> DispatchResult { ensure_root(origin)?; - if let Some(mut dummies) = Dummy::::get() { + if let Some(mut dummies) = Person::::get() { dummies.push(id.clone()); - Dummy::::set(Some(dummies)); + Person::::set(Some(dummies)); } else { - Dummy::::set(Some(vec![id.clone()])); + Person::::set(Some(vec![id.clone()])); } // Let's deposit an event to let the outside world know this happened. - Self::deposit_event(Event::AddDummy { account: id }); + Self::deposit_event(Event::AddPerson { account: id }); Ok(()) } #[pallet::call_index(1)] - pub fn set_bar( + pub fn set_points( origin: OriginFor, #[pallet::compact] new_value: T::Balance, ) -> DispatchResult { let sender = ensure_signed(origin)?; // Put the new value into storage. - >::insert(&sender, new_value); + >::insert(&sender, new_value); - Self::deposit_event(Event::SetBar { account: sender, balance: new_value }); + Self::deposit_event(Event::SetPoints { account: sender, balance: new_value }); Ok(()) } @@ -95,13 +95,13 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - AddDummy { account: T::AccountId }, - SetBar { account: T::AccountId, balance: BalanceOf }, + AddPerson { account: T::AccountId }, + SetPoints { account: T::AccountId, balance: BalanceOf }, } #[pallet::storage] - pub type Dummy = StorageValue<_, Vec>; + pub type Person = StorageValue<_, Vec>; #[pallet::storage] - pub type Bar = StorageMap<_, _, T::AccountId, T::Balance>; + pub type Points = StorageMap<_, _, T::AccountId, T::Balance>; } diff --git a/frame/examples/default-config/src/tests.rs b/frame/examples/default-config/src/tests.rs index e337c4bfe3393..fd737510bc876 100644 --- a/frame/examples/default-config/src/tests.rs +++ b/frame/examples/default-config/src/tests.rs @@ -107,24 +107,24 @@ pub fn new_test_ext() -> sp_io::TestExternalities { #[test] fn it_works_for_optional_value() { new_test_ext().execute_with(|| { - assert_eq!(Dummy::::get(), None); + assert_eq!(Person::::get(), None); let val1 = 42; - assert_ok!(Example::add_dummy(RuntimeOrigin::root(), val1)); - assert_eq!(Dummy::::get(), Some(vec![val1])); + assert_ok!(Example::add_person(RuntimeOrigin::root(), val1)); + assert_eq!(Person::::get(), Some(vec![val1])); - // Check that accumulate works when we have Some value in Dummy already. + // Check that accumulate works when we have Some value in Person already. let val2 = 27; - assert_ok!(Example::add_dummy(RuntimeOrigin::root(), val2)); - assert_eq!(Dummy::::get(), Some(vec![val1, val2])); + assert_ok!(Example::add_person(RuntimeOrigin::root(), val2)); + assert_eq!(Person::::get(), Some(vec![val1, val2])); }); } #[test] -fn set_dummy_works() { +fn set_person_works() { new_test_ext().execute_with(|| { let test_val = 133; - assert_ok!(Example::set_bar(RuntimeOrigin::signed(1), test_val.into())); - assert_eq!(Bar::::get(1), Some(test_val)); + assert_ok!(Example::set_points(RuntimeOrigin::signed(1), test_val.into())); + assert_eq!(Points::::get(1), Some(test_val)); }); } From 07a0555a14cfc1b8453dcb19e8c16ab0fd4cc5c2 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 17 May 2023 15:54:18 -0400 Subject: [PATCH 088/116] add docs to example pallet --- frame/examples/default-config/src/lib.rs | 11 ++-- frame/examples/default-config/src/tests.rs | 63 ++++++++++++++-------- frame/support/procedural/src/lib.rs | 3 ++ 3 files changed, 50 insertions(+), 27 deletions(-) diff --git a/frame/examples/default-config/src/lib.rs b/frame/examples/default-config/src/lib.rs index 2b4f9313eeae9..5cf9b40998042 100644 --- a/frame/examples/default-config/src/lib.rs +++ b/frame/examples/default-config/src/lib.rs @@ -18,12 +18,15 @@ //! //! # Default Config Pallet Example //! -//! A simple example of a FRAME pallet that utilizes `derive_impl` to implement a `DefaultConfig`. +//! A simple example of a FRAME pallet that utilizes [`frame_support::derive_impl`] to +//! implement a `DefaultConfig` for testing purposes. //! -//! Run `cargo doc --package pallet-default-config-example --open` to view this pallet's -//! documentation. +//! See the source code for `tests.rs` to see the relevant +//! [`derive_impl`](`frame_support::derive_impl`) example. //! -//! **Default test configs are not meant to be used in production** +//! Note that this pallet makes use of `dev_mode` for ease of use, since the point of this +//! example is the tests, not the pallet itself. See `pallet-dev-mode` for a more detailed +//! example of the capabilities of `dev_mode`. // Ensure we're `no_std` when compiling for WASM. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/frame/examples/default-config/src/tests.rs b/frame/examples/default-config/src/tests.rs index fd737510bc876..d4e0cd67b5c5e 100644 --- a/frame/examples/default-config/src/tests.rs +++ b/frame/examples/default-config/src/tests.rs @@ -15,16 +15,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Tests for pallet-default-config-example. +//! This module tests the `pallet-default-config-example` and serves as a reference example for +//! how to use [`derive_impl`] to vastly simplify declaring a `Test` config. +//! +//! See the comments on line 49 for a detailed explanation. use crate::*; -use frame_support::{assert_ok, traits::ConstU64}; -use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use frame_support::{assert_ok, macro_magic::use_attr, traits::ConstU64}; +use sp_runtime::{testing::Header, BuildStorage}; + +// Because `derive_impl` is a [macro_magic](https://crates.io/crates/macro_magic) attribute +// macro, [`#[use_attr]`](`frame_support::macro_magic::use_attr`) must be attached to any use +// statement that brings it into scope. +#[use_attr] +use frame_support::derive_impl; + // Reexport crate as its pallet name for construct_runtime. use crate as pallet_default_config_example; @@ -44,31 +49,43 @@ frame_support::construct_runtime!( } ); +/// Normally this impl statement would need have to have the areas that are commented out below +/// be specified manually. Attaching the `derive_impl` attribute, specifying +/// `frame_system::prelude::testing::TestDefaultConfig` as the `default_impl` and +/// `frame_system::pallet::DefaultConfig` as the `disambiguation_path` allows us to bring in +/// defaults for this impl from the `TestDefaultConfig` impl. This will fill in defaults for +/// anything in the `default_impl` that isn't present in our local impl, allowing us to +/// override the `default_impl` in any cases where we want to be explicit and differ from the +/// `default_impl`. +#[derive_impl(frame_system::prelude::testing::TestDefaultConfig as frame_system::pallet::DefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); + // type BlockWeights = (); + // type BlockLength = (); + // type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; - type Index = u64; + // type Index = u64; type BlockNumber = u64; - type Hash = H256; + // type Hash = sp_core::H256; type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; + // type Hashing = BlakeTwo256; + // type AccountId = u64; + // type Lookup = IdentityLookup; type Header = Header; type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); + // type BlockHashCount = ConstU64<250>; + // type Version = (); type PalletInfo = PalletInfo; + + /// we override `AccountData`, since we want a u64 not a u32. type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); + + // type OnNewAccount = (); + // type OnKilledAccount = (); + // type SystemWeightInfo = (); + // type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + // type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 7c6a731b6466f..95ca8d917a945 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -968,6 +968,9 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// `Test`), unless the trait item in the local trait impl is marked with /// [`#[pallet::no_default]`](`macro@default_config`), in which case it cannot be overridden, /// and any attempts to do so will result in a compiler error. +/// +/// See `frame/examples/default-config/tests.rs` for a runnable end-to-end example pallet that +/// makes use of `derive_impl` to derive its testing config. #[import_tokens_attr(frame_support::macro_magic)] #[with_custom_parsing(derive_impl::DeriveImplAttrArgs)] #[proc_macro_attribute] From cc7bd842bb134372fb53c5b4cbd55a0491b56577 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 18 May 2023 16:50:34 -0400 Subject: [PATCH 089/116] revert changes to pallets other than the default config example --- frame/balances/src/lib.rs | 4 +--- frame/examples/basic/src/lib.rs | 5 +--- frame/examples/basic/src/tests.rs | 39 ++++++++++++++++++++----------- frame/nomination-pools/src/lib.rs | 6 +---- 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 2b1f89173e1e4..b3dc77a9b879d 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -213,7 +213,7 @@ pub mod pallet { pub type CreditOf = Credit<::AccountId, Pallet>; - #[pallet::default_config] + #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. type RuntimeEvent: From> @@ -236,7 +236,6 @@ pub mod pallet { + FixedPointOperand; /// Handler for the unbalanced reduction when removing a dust account. - #[pallet::no_default] type DustRemoval: OnUnbalanced>; /// The minimum amount required to keep an account open. MUST BE GREATER THAN ZERO! @@ -251,7 +250,6 @@ pub mod pallet { type ExistentialDeposit: Get; /// The means of storing the balances of an account. - #[pallet::no_default] type AccountStore: StoredMap>; /// The ID type for reserves. diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index e06e86c0e964a..bbeaac19f809c 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -363,13 +363,10 @@ pub mod pallet { /// should be added to our implied traits list. /// /// `frame_system::Config` should always be included. - #[pallet::default_config] + #[pallet::config] pub trait Config: pallet_balances::Config + frame_system::Config { // Setting a constant config parameter from the runtime #[pallet::constant] - #[pallet::no_default] - // It is very unfortunate that we cannot have this have a default either, because it relies - // on `` type MagicNumber: Get; /// The overarching event type. diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index a069a229f1f16..1d9cf81a5074c 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -21,19 +21,19 @@ use crate::*; use frame_support::{ assert_ok, dispatch::{DispatchInfo, GetDispatchInfo}, - macro_magic::use_attr, traits::{ConstU64, OnInitialize}, }; - +use sp_core::H256; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. -use sp_runtime::{testing::Header, BuildStorage}; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, +}; // Reexport crate as its pallet name for construct_runtime. use crate as pallet_example_basic; -#[use_attr] -use frame_support::derive_impl; - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -50,18 +50,31 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::prelude::testing::TestDefaultConfig as frame_system::pallet::DefaultConfig)] impl frame_system::Config for Test { - // These are all defined by system as mandatory. type BaseCallFilter = frame_support::traits::Everything; - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; - type OnSetCode = (); - type PalletInfo = PalletInfo; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type RuntimeCall = RuntimeCall; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; type Header = Header; - // We decide to override this one. + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 2e91faf4c195f..78f0c730ce5dd 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1502,7 +1502,7 @@ pub mod pallet { #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); - #[pallet::default_config] + #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -1511,7 +1511,6 @@ pub mod pallet { type WeightInfo: weights::WeightInfo; /// The nominating balance. - #[pallet::no_default] type Currency: Currency; /// The type that is used for reward counter. @@ -1548,15 +1547,12 @@ pub mod pallet { type MaxPointsToBalance: Get; /// Infallible method for converting `Currency::Balance` to `U256`. - #[pallet::no_default] type BalanceToU256: Convert, U256>; /// Infallible method for converting `U256` to `Currency::Balance`. - #[pallet::no_default] type U256ToBalance: Convert>; /// The interface for nominating. - #[pallet::no_default] type Staking: StakingInterface, AccountId = Self::AccountId>; /// The amount of eras a `SubPools::with_era` pool can exist before it gets merged into the From b4b7de8c9da89596912d24407f6b971c25341ba6 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 18 May 2023 16:58:06 -0400 Subject: [PATCH 090/116] fix outdated references to basic example pallet --- frame/support/procedural/src/lib.rs | 2 +- frame/system/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 276452de08bb9..f444d33ad4b75 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -879,7 +879,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// the path to the auto-generated `DefaultConfig` for the existing pallet `Config` we want to /// base our test config off of. /// -/// Consider the following taken from the `basic` example pallet: +/// The following is what the `basic` example pallet would look like with a default testing config: /// /// ```ignore /// #[derive_impl(frame_system::prelude::testing::TestDefaultConfig as frame_system::pallet::DefaultConfig)] diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 705e0f7ff742b..2d6334d5549e8 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -212,8 +212,8 @@ pub mod pallet { /// [`derive_impl`](`frame_support::derive_impl`) to derive a testing pallet config /// based on this one. /// - /// See `Test` in the "basic" example pallet's `test.rs` for an example of a - /// downstream user of this particular `TestDefaultConfig` + /// See `Test` in the `default-config` example pallet's `test.rs` for an example of + /// a downstream user of this particular `TestDefaultConfig` pub struct TestDefaultConfig; #[register_default_impl(TestDefaultConfig)] From 13d5ab4f8210519954e2bfe3951ae040bf6ddbe0 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 18 May 2023 17:12:13 -0400 Subject: [PATCH 091/116] re-order docs to be a bit more clear --- frame/support/procedural/src/lib.rs | 78 +++++++++++++++-------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index f444d33ad4b75..f64ae80d50da8 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -785,7 +785,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// /// For a full end-to-end example, see [below](#use-case-auto-derive-test-pallet-config-traits). /// -/// ## Usage +/// # Usage /// /// The attribute should be attached to an impl block (strictly speaking a `syn::ItemImpl`) for /// which we want to inject defaults in the event of missing trait items in the block. @@ -829,43 +829,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// locally in the context of the foreign impl and the pallet (or context) in which it is /// defined. /// -/// ## Importing & Re-Exporting -/// -/// Since `#[derive_impl(..)]` is a -/// [`macro_magic`](https://docs.rs/macro_magic/latest/macro_magic/)-based attribute macro, -/// special care must be taken when importing and re-exporting it. Glob imports will work -/// properly, such as `use frame_support::*` to bring `derive_impl` into scope, however any -/// other use statements involving `derive_impl` should have -/// [`#[macro_magic::use_attr]`](https://docs.rs/macro_magic/latest/macro_magic/attr.use_attr.html) -/// attached or your use statement will fail to fully bring the macro into scope. -/// -/// This brings `derive_impl` into scope in the current context: -/// ```ignore -/// #[use_attr] -/// use frame_support::derive_impl; -/// ``` -/// -/// This brings `derive_impl` into scope and publicly re-exports it from the current context: -/// ```ignore -/// #[use_attr] -/// pub use frame_support::derive_impl; -/// ``` -/// -/// ## Expansion -/// -/// The `#[derive_impl(default_impl_path as disambiguation_path)]` attribute will expand to the -/// local impl, with any extra items from the foreign impl that aren't present in the local -/// impl also included. In the case of a colliding trait item, the version of the item that -/// exists in the local impl will be retained. All imported items are qualified by the -/// `disambiguation_path`, as discussed above. -/// -/// ## Handling of Unnamed Trait Items -/// -/// Items that lack a `syn::Ident` for whatever reason are first checked to see if they -/// exist, verbatim, in the local/destination trait before they are copied over, so you should -/// not need to worry about collisions between identical unnamed items. -/// -/// ## Use-Case: Auto-Derive Test Pallet Config Traits +/// ## Use-Case Example: Auto-Derive Test Pallet Config Traits /// /// The `#[derive_imp(..)]` attribute can be used to derive a test pallet `Config` based on an /// existing pallet `Config` that has been marked with @@ -969,6 +933,44 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// /// See `frame/examples/default-config/tests.rs` for a runnable end-to-end example pallet that /// makes use of `derive_impl` to derive its testing config. +/// +/// # Advanced Usage +/// +/// ## Importing & Re-Exporting +/// +/// Since `#[derive_impl(..)]` is a +/// [`macro_magic`](https://docs.rs/macro_magic/latest/macro_magic/)-based attribute macro, +/// special care must be taken when importing and re-exporting it. Glob imports will work +/// properly, such as `use frame_support::*` to bring `derive_impl` into scope, however any +/// other use statements involving `derive_impl` should have +/// [`#[macro_magic::use_attr]`](https://docs.rs/macro_magic/latest/macro_magic/attr.use_attr.html) +/// attached or your use statement will fail to fully bring the macro into scope. +/// +/// This brings `derive_impl` into scope in the current context: +/// ```ignore +/// #[use_attr] +/// use frame_support::derive_impl; +/// ``` +/// +/// This brings `derive_impl` into scope and publicly re-exports it from the current context: +/// ```ignore +/// #[use_attr] +/// pub use frame_support::derive_impl; +/// ``` +/// +/// ## Expansion +/// +/// The `#[derive_impl(default_impl_path as disambiguation_path)]` attribute will expand to the +/// local impl, with any extra items from the foreign impl that aren't present in the local +/// impl also included. In the case of a colliding trait item, the version of the item that +/// exists in the local impl will be retained. All imported items are qualified by the +/// `disambiguation_path`, as discussed above. +/// +/// ## Handling of Unnamed Trait Items +/// +/// Items that lack a `syn::Ident` for whatever reason are first checked to see if they +/// exist, verbatim, in the local/destination trait before they are copied over, so you should +/// not need to worry about collisions between identical unnamed items. #[import_tokens_attr(frame_support::macro_magic)] #[with_custom_parsing(derive_impl::DeriveImplAttrArgs)] #[proc_macro_attribute] From b9113c4794ebd1e476816cf77a234b716b8f087a Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 18 May 2023 18:02:10 -0400 Subject: [PATCH 092/116] better errors for extra attributes --- .../procedural/src/pallet/parse/config.rs | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index b4afea1e1d9c9..80c183d90d1b7 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -347,22 +347,37 @@ impl ConfigDef { let is_event = check_event_type(frame_system, trait_item, has_instance)?; let mut no_default = false; has_event_type = has_event_type || is_event; + let mut already_constant = false; - for _ in 0..2 { - if let Ok(Some(pallet_attr)) = - helper::take_first_item_pallet_attr::(trait_item) - { - match (pallet_attr.typ, &trait_item) { - (PalletAttrType::Constant(_), syn::TraitItem::Type(ref typ)) => - consts_metadata.push(ConstMetadataDef::try_from(typ)?), - (PalletAttrType::Constant(_), _) => + while let Ok(Some(pallet_attr)) = + helper::take_first_item_pallet_attr::(trait_item) + { + match (pallet_attr.typ, &trait_item) { + (PalletAttrType::Constant(_), syn::TraitItem::Type(ref typ)) => { + if already_constant { return Err(syn::Error::new( - trait_item.span(), - "Invalid pallet::constant in pallet::config, expected \ + pallet_attr._bracket.span.join(), + "Duplicate #[pallet::constant] attribute not allowed.", + )) + } + already_constant = true; + consts_metadata.push(ConstMetadataDef::try_from(typ)?); + }, + (PalletAttrType::Constant(_), _) => + return Err(syn::Error::new( + trait_item.span(), + "Invalid pallet::constant in pallet::config, expected \ type trait item", - )), - (PalletAttrType::NoDefault(_), _) => no_default = true, - } + )), + (PalletAttrType::NoDefault(_), _) => { + if no_default { + return Err(syn::Error::new( + pallet_attr._bracket.span.join(), + "Duplicate #[pallet::no_default] attribute not allowed.", + )) + } + no_default = true; + }, } } From 9d4cce6847ddeb3fc6498e5a5e4234e1b4a94c49 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 18 May 2023 21:14:26 -0400 Subject: [PATCH 093/116] add UI tests for duplicate/extra attributes on trait items --- .../trait_item_duplicate_constant_attr.rs | 23 ++++++++++++++++++ .../trait_item_duplicate_constant_attr.stderr | 5 ++++ .../trait_item_duplicate_no_default.rs | 24 +++++++++++++++++++ .../trait_item_duplicate_no_default.stderr | 5 ++++ 4 files changed, 57 insertions(+) create mode 100644 frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.rs create mode 100644 frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.stderr create mode 100644 frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.rs create mode 100644 frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.stderr diff --git a/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.rs b/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.rs new file mode 100644 index 0000000000000..8f3d9f3f3e2f9 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.rs @@ -0,0 +1,23 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + #[pallet::constant] + #[pallet::constant] + type MyGetParam2: Get; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} +} + +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.stderr b/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.stderr new file mode 100644 index 0000000000000..3679b67f07b53 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/trait_item_duplicate_constant_attr.stderr @@ -0,0 +1,5 @@ +error: Duplicate #[pallet::constant] attribute not allowed. + --> tests/pallet_ui/trait_item_duplicate_constant_attr.rs:9:4 + | +9 | #[pallet::constant] + | ^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.rs b/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.rs new file mode 100644 index 0000000000000..8699c20828002 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.rs @@ -0,0 +1,24 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + #[pallet::constant] + #[pallet::no_default] + #[pallet::no_default] + type MyGetParam2: Get; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} +} + +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.stderr b/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.stderr new file mode 100644 index 0000000000000..77a29c394d62d --- /dev/null +++ b/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.stderr @@ -0,0 +1,5 @@ +error: Duplicate #[pallet::no_default] attribute not allowed. + --> tests/pallet_ui/trait_item_duplicate_no_default.rs:10:4 + | +10 | #[pallet::no_default] + | ^^^^^^^^^^^^^^^^^^^^ From 167cbbd50af1d95bb419e5bc0f299b180a3afe99 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Mon, 22 May 2023 19:21:02 -0400 Subject: [PATCH 094/116] change `#[pallet::default_config]` to option on `#[pallet::config()]` * update UI tests * add UI test covering missing `#[pallet::config(with_default)]` when `#[pallet::no_default]` is used --- frame/examples/default-config/README.md | 2 +- frame/support/procedural/src/lib.rs | 62 +++++++++++-------- .../procedural/src/pallet/expand/config.rs | 2 +- .../procedural/src/pallet/parse/config.rs | 11 +++- .../procedural/src/pallet/parse/mod.rs | 33 +++++----- .../no_default_but_missing_with_default.rs | 23 +++++++ ...no_default_but_missing_with_default.stderr | 5 ++ .../trait_item_duplicate_no_default.rs | 2 +- frame/system/src/lib.rs | 2 +- 9 files changed, 97 insertions(+), 45 deletions(-) create mode 100644 frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.rs create mode 100644 frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr diff --git a/frame/examples/default-config/README.md b/frame/examples/default-config/README.md index 068198b24b430..e8935d2c52661 100644 --- a/frame/examples/default-config/README.md +++ b/frame/examples/default-config/README.md @@ -1,7 +1,7 @@ # Default Config Example Pallet An example pallet demonstrating the ability to derive default testing configs via the -`derive_impl` and `#[pallet::default_config]` macros. +`derive_impl` and `#[pallet::config(with_default)]`. Run `cargo doc --package pallet-default-config-example --open` to view this pallet's documentation. diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index f64ae80d50da8..74403e5ee84f7 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -833,7 +833,7 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// /// The `#[derive_imp(..)]` attribute can be used to derive a test pallet `Config` based on an /// existing pallet `Config` that has been marked with -/// [`#[pallet::default_config]`](`macro@default_config`) (which under the hood, generates a +/// [`#[pallet::config(with_default)]`](`macro@config`) (which under the hood, generates a /// `DefaultConfig` trait in the pallet in which the macro was invoked). /// /// In this case, the `#[derive_impl(..)]` attribute should be attached to an `impl` block that @@ -924,12 +924,11 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// /// You can then use the resulting `Test` config in test scenarios. /// -/// Note that items that are _not_ present in our local -/// [`#[pallet::default_config]`](`macro@default_config`) are automatically copied from the -/// foreign trait (in this case `TestDefaultConfig`) into the local trait impl (in this case -/// `Test`), unless the trait item in the local trait impl is marked with -/// [`#[pallet::no_default]`](`macro@default_config`), in which case it cannot be overridden, -/// and any attempts to do so will result in a compiler error. +/// Note that items that are _not_ present in our local `DefaultConfig` are automatically +/// copied from the foreign trait (in this case `TestDefaultConfig`) into the local trait impl +/// (in this case `Test`), unless the trait item in the local trait impl is marked with +/// [`#[pallet::no_default]`](`macro@no_default`), in which case it cannot be overridden, and +/// any attempts to do so will result in a compiler error. /// /// See `frame/examples/default-config/tests.rs` for a runnable end-to-end example pallet that /// makes use of `derive_impl` to derive its testing config. @@ -986,25 +985,8 @@ pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { .into() } -/// The optional attribute `#[pallet::default_config]` can be attached to a `Config` trait -/// within your pallet to mark it as auto-derivable under test conditions via -/// [`[#[derive_impl(..)]`](`macro@derive_impl`). -/// -/// You may use [`#[pallet::no_default]`](`macro@no_default`) and -/// [`#[pallet::constant]`](`macro@constant`) on individual trait items within your `Config` -/// trait. -/// -/// The [`#[pallet::no_default]`](`macro@no_default`) attribute allows you to specify that a -/// particular trait item _cannot_ be used as a default when a test `Config` is derived using -/// the [`#[derive_impl(..)]`](`macro@derive_impl`) attribute macro. -#[proc_macro_attribute] -pub fn default_config(_: TokenStream, _: TokenStream) -> TokenStream { - pallet_macro_stub() -} - /// The optional attribute `#[pallet::no_default]` can be attached to trait items within a -/// `Config` trait impl that has [`#[pallet::default_config]`](`macro@default_config`) attached -/// to it. +/// `Config` trait impl that has [`#[pallet::config(with_default)]`](`macro@config`) attached. /// /// Attaching this attribute to a trait item ensures that that trait item will not be used as a /// default with the [`#[derive_impl(..)]`](`macro@derive_impl`) attribute macro. @@ -1081,6 +1063,36 @@ fn pallet_macro_stub() -> TokenStream { /// /// [`pallet::event`](`macro@event`) must be present if `RuntimeEvent` exists as a config item /// in your `#[pallet::config]`. +/// +/// ## Optional: `with_default` +/// +/// An optional `with_default` argument may also be specified. Doing so will automatically +/// generate a `DefaultConfig` trait inside your pallet which is suitable for use with +/// [`[#[derive_impl(..)]`](`macro@derive_impl`) to derive a default testing config. The +/// following demonstrates this syntax: +/// +/// ```ignore +/// #[pallet::config(with_default)] +/// pub trait Config: frame_system::Config { +/// type RuntimeEvent: Parameter +/// + Member +/// + From> +/// + Debug +/// + IsType<::RuntimeEvent>; +/// +/// #[pallet::no_default] +/// type BaseCallFilter: Contains; +/// // ... +/// } +/// ``` +/// +/// As shown above, you may also attach the [`#[pallet::no_default]`](`macro@no_default`) +/// attribute to specify that a particular trait item _cannot_ be used as a default when a test +/// `Config` is derived using the [`#[derive_impl(..)]`](`macro@derive_impl`) attribute macro. +/// This will cause that particular trait item to simply not appear in default testing configs +/// based on this config. +/// +/// For more information, see [`macro@derive_impl`]. #[proc_macro_attribute] pub fn config(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index 3a5f8efe929db..9abf66fe8962c 100644 --- a/frame/support/procedural/src/pallet/expand/config.rs +++ b/frame/support/procedural/src/pallet/expand/config.rs @@ -50,7 +50,7 @@ pub fn expand_config(def: &mut Def) -> TokenStream { let trait_items = &config.default_sub_trait; quote!( /// Based on [`Config`]. Auto-generated by - /// [`#[pallet::default_config]`](`frame_support::pallet_macros::default_config`). + /// [`#[pallet::config(with_default)]`](`frame_support::pallet_macros::config`). /// Can be used in tandem with /// [`#[register_default_config]`](`frame_support::register_default_config`) and /// [`#[derive_impl]`](`frame_support::derive_impl`) to derive test config traits diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 80c183d90d1b7..417ca06962154 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -57,8 +57,8 @@ pub struct ConfigDef { /// Whether a default sub-trait should be generated. /// /// Contains default sub-trait items (instantiated by `#[pallet::default_config]`). Vec - /// will be empty if `#[pallet::default_config]` is not specified or if there are no trait - /// items + /// will be empty if `#[pallet::config(with_default)]` is not specified or if there are no + /// trait items pub default_sub_trait: Vec, } @@ -370,6 +370,13 @@ impl ConfigDef { type trait item", )), (PalletAttrType::NoDefault(_), _) => { + if !enable_default { + return Err(syn::Error::new( + pallet_attr._bracket.span.join(), + "`#[pallet:no_default]` can only be used if `#[pallet::config(with_default)]` \ + has been specified" + )) + } if no_default { return Err(syn::Error::new( pallet_attr._bracket.span.join(), diff --git a/frame/support/procedural/src/pallet/parse/mod.rs b/frame/support/procedural/src/pallet/parse/mod.rs index fe0284e74f45c..4a4602964a996 100644 --- a/frame/support/procedural/src/pallet/parse/mod.rs +++ b/frame/support/procedural/src/pallet/parse/mod.rs @@ -100,12 +100,14 @@ impl Def { let pallet_attr: Option = helper::take_first_item_pallet_attr(item)?; match pallet_attr { - Some(PalletAttr::Config(span)) if config.is_none() => - config = - Some(config::ConfigDef::try_from(&frame_system, span, index, item, false)?), - Some(PalletAttr::DefaultConfig(span)) if config.is_none() => - config = - Some(config::ConfigDef::try_from(&frame_system, span, index, item, true)?), + Some(PalletAttr::Config(span, with_default)) if config.is_none() => + config = Some(config::ConfigDef::try_from( + &frame_system, + span, + index, + item, + with_default, + )?), Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => { let p = pallet_struct::PalletStructDef::try_from(span, index, item)?; pallet_struct = Some(p); @@ -409,7 +411,7 @@ mod keyword { syn::custom_keyword!(weight); syn::custom_keyword!(event); syn::custom_keyword!(config); - syn::custom_keyword!(default_config); + syn::custom_keyword!(with_default); syn::custom_keyword!(hooks); syn::custom_keyword!(inherent); syn::custom_keyword!(error); @@ -428,8 +430,7 @@ mod keyword { /// Parse attributes for item in pallet module /// syntax must be `pallet::` (e.g. `#[pallet::config]`) enum PalletAttr { - Config(proc_macro2::Span), - DefaultConfig(proc_macro2::Span), + Config(proc_macro2::Span, bool), Pallet(proc_macro2::Span), Hooks(proc_macro2::Span), /// A `#[pallet::call]` with optional attributes to specialize the behaviour. @@ -486,8 +487,7 @@ enum PalletAttr { impl PalletAttr { fn span(&self) -> proc_macro2::Span { match self { - Self::Config(span) => *span, - Self::DefaultConfig(span) => *span, + Self::Config(span, _) => *span, Self::Pallet(span) => *span, Self::Hooks(span) => *span, Self::RuntimeCall(_, span) => *span, @@ -516,9 +516,14 @@ impl syn::parse::Parse for PalletAttr { let lookahead = content.lookahead1(); if lookahead.peek(keyword::config) { - Ok(PalletAttr::Config(content.parse::()?.span())) - } else if lookahead.peek(keyword::default_config) { - Ok(PalletAttr::DefaultConfig(content.parse::()?.span())) + let span = content.parse::()?.span(); + let with_default = content.peek(syn::token::Paren); + if with_default { + let inside_config; + let _paren = syn::parenthesized!(inside_config in content); + inside_config.parse::()?; + } + Ok(PalletAttr::Config(span, with_default)) } else if lookahead.peek(keyword::pallet) { Ok(PalletAttr::Pallet(content.parse::()?.span())) } else if lookahead.peek(keyword::hooks) { diff --git a/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.rs b/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.rs new file mode 100644 index 0000000000000..5ffa13c22243d --- /dev/null +++ b/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.rs @@ -0,0 +1,23 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + #[pallet::constant] + #[pallet::no_default] + type MyGetParam2: Get; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} +} + +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr b/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr new file mode 100644 index 0000000000000..aebde115eb80e --- /dev/null +++ b/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr @@ -0,0 +1,5 @@ +error: `#[pallet:no_default]` can only be used if `#[pallet::config(with_default)]` has been specified + --> tests/pallet_ui/no_default_but_missing_with_default.rs:9:4 + | +9 | #[pallet::no_default] + | ^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.rs b/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.rs index 8699c20828002..d2040ec74dc4e 100644 --- a/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.rs +++ b/frame/support/test/tests/pallet_ui/trait_item_duplicate_no_default.rs @@ -3,7 +3,7 @@ mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - #[pallet::config] + #[pallet::config(with_default)] pub trait Config: frame_system::Config { #[pallet::constant] #[pallet::no_default] diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 2d6334d5549e8..9b1fc8e7248a6 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -240,7 +240,7 @@ pub mod pallet { } /// System configuration trait. Implemented by runtime. - #[pallet::default_config] + #[pallet::config(with_default)] #[pallet::disable_frame_system_supertrait_check] pub trait Config: 'static + Eq + Clone { /// The aggregated event type of the runtime. From c8640d4fcde3f284babdf16da370f65d848f7771 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Mon, 22 May 2023 22:16:36 -0400 Subject: [PATCH 095/116] add note about new optional conventions --- frame/support/procedural/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 74403e5ee84f7..c3ef01f5edacf 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -933,6 +933,15 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// See `frame/examples/default-config/tests.rs` for a runnable end-to-end example pallet that /// makes use of `derive_impl` to derive its testing config. /// +/// ## Optional Conventions +/// +/// Note that as an optional convention, we encourage creating a `prelude` module inside of +/// your pallet with sub-modules for `testing`, `production` etc.. This is the convention we +/// follow for `frame_system`'s `TestDefaultConfig` which, as shown above, is located at +/// `frame_system::prelude::testing::TestDefaultConfig`. This is just a suggested convention -- +/// there is nothing in the code that expects modules with these names to be in place, so there +/// is no imperative to follow this pattern unless desired. +/// /// # Advanced Usage /// /// ## Importing & Re-Exporting From bb4f8fd1d2170d22542ab86add59639be2930296 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Mon, 22 May 2023 23:47:52 -0400 Subject: [PATCH 096/116] improve docs about `DefaultConfig` and link to these from a few places --- frame/support/procedural/src/lib.rs | 25 ++++++++++++++++--- .../procedural/src/pallet/expand/config.rs | 3 +++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index c3ef01f5edacf..12e3e6f78ed03 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -933,6 +933,9 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// See `frame/examples/default-config/tests.rs` for a runnable end-to-end example pallet that /// makes use of `derive_impl` to derive its testing config. /// +/// See [here](`macro@config`) for more information and caveats about the auto-generated +/// `DefaultConfig` trait. +/// /// ## Optional Conventions /// /// Note that as an optional convention, we encourage creating a `prelude` module inside of @@ -1077,8 +1080,7 @@ fn pallet_macro_stub() -> TokenStream { /// /// An optional `with_default` argument may also be specified. Doing so will automatically /// generate a `DefaultConfig` trait inside your pallet which is suitable for use with -/// [`[#[derive_impl(..)]`](`macro@derive_impl`) to derive a default testing config. The -/// following demonstrates this syntax: +/// [`[#[derive_impl(..)]`](`macro@derive_impl`) to derive a default testing config: /// /// ```ignore /// #[pallet::config(with_default)] @@ -1099,7 +1101,24 @@ fn pallet_macro_stub() -> TokenStream { /// attribute to specify that a particular trait item _cannot_ be used as a default when a test /// `Config` is derived using the [`#[derive_impl(..)]`](`macro@derive_impl`) attribute macro. /// This will cause that particular trait item to simply not appear in default testing configs -/// based on this config. +/// based on this config (the trait item will not be included in `DefaultConfig`). +/// +/// ### `DefaultConfig` Caveats +/// +/// The auto-generated `DefaultConfig` trait: +/// - is always a _subset_ of your pallet's `Config` trait. +/// - can only contain items that don't rely on externalities, such as `frame_system::Config`. +/// +/// Trait items that _do_ rely on externalities should be marked with +/// [`#[pallet::no_default]`](`macro@no_default`) +/// +/// Consequently: +/// - Any items that rely on externalities _must_ be marked with +/// [`#[pallet::no_default]`](`macro@no_default`) or your trait will fail to compile when used +/// with [`derive_impl`](`macro@derive_impl`). +/// - Items marked with [`#[pallet::no_default]`](`macro@no_default`) are entirely excluded from the +/// `DefaultConfig` trait, and therefore any impl of `DefaultConfig` doesn't need to implement +/// such items. /// /// For more information, see [`macro@derive_impl`]. #[proc_macro_attribute] diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index 9abf66fe8962c..7e7c8e388f474 100644 --- a/frame/support/procedural/src/pallet/expand/config.rs +++ b/frame/support/procedural/src/pallet/expand/config.rs @@ -55,6 +55,9 @@ pub fn expand_config(def: &mut Def) -> TokenStream { /// [`#[register_default_config]`](`frame_support::register_default_config`) and /// [`#[derive_impl]`](`frame_support::derive_impl`) to derive test config traits /// based on existing pallet config traits in a safe and developer-friendly way. + /// + /// See [here](`frame_support::pallet_macros::config`) for more information and caveats about + /// the auto-generated `DefaultConfig` trait and how it is generated. pub trait DefaultConfig { #(#trait_items)* } From 1029ff68d554cbc2bf115487178133c9bbee7be0 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Mon, 22 May 2023 23:50:33 -0400 Subject: [PATCH 097/116] fix doc comment --- frame/examples/default-config/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/examples/default-config/README.md b/frame/examples/default-config/README.md index e8935d2c52661..b1a67a5c16e55 100644 --- a/frame/examples/default-config/README.md +++ b/frame/examples/default-config/README.md @@ -1,7 +1,7 @@ # Default Config Example Pallet -An example pallet demonstrating the ability to derive default testing configs via the -`derive_impl` and `#[pallet::config(with_default)]`. +An example pallet demonstrating the ability to derive default testing configs via +`#[derive_impl]` and `#[pallet::config(with_default)]`. Run `cargo doc --package pallet-default-config-example --open` to view this pallet's documentation. From 86b649cc83da9fa69fdedd3e37ac2dd0a819e85a Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Mon, 22 May 2023 23:53:43 -0400 Subject: [PATCH 098/116] fix old comment referencing `pallet::default_config` --- frame/support/procedural/src/pallet/parse/config.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 417ca06962154..d538c7f999952 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -56,9 +56,9 @@ pub struct ConfigDef { pub attr_span: proc_macro2::Span, /// Whether a default sub-trait should be generated. /// - /// Contains default sub-trait items (instantiated by `#[pallet::default_config]`). Vec - /// will be empty if `#[pallet::config(with_default)]` is not specified or if there are no - /// trait items + /// Contains default sub-trait items (instantiated by `#[pallet::config(with_default)]`). + /// Vec will be empty if `#[pallet::config(with_default)]` is not specified or if there are + /// no trait items pub default_sub_trait: Vec, } From fc7b8aa495718280031db2e402adf40d2348cbb9 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 24 May 2023 08:26:18 -0400 Subject: [PATCH 099/116] use u32 instead of u64 for block number Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/system/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 9b1fc8e7248a6..2c9a2455d6ed7 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -223,7 +223,7 @@ pub mod pallet { type BlockLength = (); type DbWeight = (); type Index = u64; - type BlockNumber = u64; + type BlockNumber = u32; type Hash = sp_core::hash::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; From 09c30c1842fca0746691f0aa790624c09d9b8eb3 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 24 May 2023 08:26:50 -0400 Subject: [PATCH 100/116] use () instead of u32 for `AccountData` Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/system/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 2c9a2455d6ed7..3ab7b1da6576f 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -229,7 +229,7 @@ pub mod pallet { type AccountId = AccountId; type Lookup = IdentityLookup; type BlockHashCount = frame_support::traits::ConstU64<10>; - type AccountData = u32; + type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); From 0b21ac14840db25550dca55f63bf17b52d24a17f Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 24 May 2023 08:27:33 -0400 Subject: [PATCH 101/116] use ConstU32<10> for BlockHashCount instead of ConstU64<10> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/system/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 3ab7b1da6576f..b0379298418e2 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -228,7 +228,7 @@ pub mod pallet { type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; - type BlockHashCount = frame_support::traits::ConstU64<10>; + type BlockHashCount = frame_support::traits::ConstU32<10>; type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); From 144c09d8e895b8baac4f6d448620cea3fdb71235 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 24 May 2023 08:29:26 -0400 Subject: [PATCH 102/116] people are not dummies Co-authored-by: Liam Aharon --- frame/examples/default-config/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/examples/default-config/src/lib.rs b/frame/examples/default-config/src/lib.rs index 5cf9b40998042..0e8ad04010118 100644 --- a/frame/examples/default-config/src/lib.rs +++ b/frame/examples/default-config/src/lib.rs @@ -66,9 +66,9 @@ pub mod pallet { pub fn add_person(origin: OriginFor, id: T::AccountId) -> DispatchResult { ensure_root(origin)?; - if let Some(mut dummies) = Person::::get() { - dummies.push(id.clone()); - Person::::set(Some(dummies)); + if let Some(mut people) = Person::::get() { + people.push(id.clone()); + Person::::set(Some(people)); } else { Person::::set(Some(vec![id.clone()])); } From d86021e4ccd4c86dd58cf39ec43440d32a26aac0 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 24 May 2023 08:32:16 -0400 Subject: [PATCH 103/116] fix wording Co-authored-by: Just van Stam --- frame/examples/default-config/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/examples/default-config/src/tests.rs b/frame/examples/default-config/src/tests.rs index d4e0cd67b5c5e..22725c3a56f3d 100644 --- a/frame/examples/default-config/src/tests.rs +++ b/frame/examples/default-config/src/tests.rs @@ -49,7 +49,7 @@ frame_support::construct_runtime!( } ); -/// Normally this impl statement would need have to have the areas that are commented out below +/// Normally this impl statement would need to have the areas that are commented out below /// be specified manually. Attaching the `derive_impl` attribute, specifying /// `frame_system::prelude::testing::TestDefaultConfig` as the `default_impl` and /// `frame_system::pallet::DefaultConfig` as the `disambiguation_path` allows us to bring in From db8587f96925f5ae674191b306ddd8d07a729755 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 24 May 2023 08:47:42 -0400 Subject: [PATCH 104/116] Person => People and compiling again --- frame/examples/default-config/src/lib.rs | 12 ++++++------ frame/examples/default-config/src/tests.rs | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/frame/examples/default-config/src/lib.rs b/frame/examples/default-config/src/lib.rs index 0e8ad04010118..3a609e81a07c3 100644 --- a/frame/examples/default-config/src/lib.rs +++ b/frame/examples/default-config/src/lib.rs @@ -66,15 +66,15 @@ pub mod pallet { pub fn add_person(origin: OriginFor, id: T::AccountId) -> DispatchResult { ensure_root(origin)?; - if let Some(mut people) = Person::::get() { + if let Some(mut people) = People::::get() { people.push(id.clone()); - Person::::set(Some(people)); + People::::set(Some(people)); } else { - Person::::set(Some(vec![id.clone()])); + People::::set(Some(vec![id.clone()])); } // Let's deposit an event to let the outside world know this happened. - Self::deposit_event(Event::AddPerson { account: id }); + Self::deposit_event(Event::AddPeople { account: id }); Ok(()) } @@ -98,12 +98,12 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - AddPerson { account: T::AccountId }, + AddPeople { account: T::AccountId }, SetPoints { account: T::AccountId, balance: BalanceOf }, } #[pallet::storage] - pub type Person = StorageValue<_, Vec>; + pub type People = StorageValue<_, Vec>; #[pallet::storage] pub type Points = StorageMap<_, _, T::AccountId, T::Balance>; diff --git a/frame/examples/default-config/src/tests.rs b/frame/examples/default-config/src/tests.rs index 22725c3a56f3d..9f356e6688d1c 100644 --- a/frame/examples/default-config/src/tests.rs +++ b/frame/examples/default-config/src/tests.rs @@ -73,7 +73,7 @@ impl frame_system::Config for Test { // type Lookup = IdentityLookup; type Header = Header; type RuntimeEvent = RuntimeEvent; - // type BlockHashCount = ConstU64<250>; + type BlockHashCount = ConstU64<250>; // type Version = (); type PalletInfo = PalletInfo; @@ -124,16 +124,16 @@ pub fn new_test_ext() -> sp_io::TestExternalities { #[test] fn it_works_for_optional_value() { new_test_ext().execute_with(|| { - assert_eq!(Person::::get(), None); + assert_eq!(People::::get(), None); let val1 = 42; assert_ok!(Example::add_person(RuntimeOrigin::root(), val1)); - assert_eq!(Person::::get(), Some(vec![val1])); + assert_eq!(People::::get(), Some(vec![val1])); - // Check that accumulate works when we have Some value in Person already. + // Check that accumulate works when we have Some value in People already. let val2 = 27; assert_ok!(Example::add_person(RuntimeOrigin::root(), val2)); - assert_eq!(Person::::get(), Some(vec![val1, val2])); + assert_eq!(People::::get(), Some(vec![val1, val2])); }); } From 4ffda9b71e1f2c7a86255141945e3b5b3f5787b8 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 24 May 2023 08:56:30 -0400 Subject: [PATCH 105/116] add docs for `prelude` module in frame_system --- frame/system/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index b0379298418e2..16467c60d5e69 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -201,8 +201,11 @@ pub mod pallet { use crate::{self as frame_system, pallet_prelude::*, *}; use frame_support::pallet_prelude::*; + /// Contains default types suitable for various environments pub mod prelude { use super::*; + + /// Contains default types suitable for testing purposes pub mod testing { type AccountId = u64; use super::*; From 2f8f4a54c7648ece2d426fa705e49ba05ee29ab8 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 24 May 2023 13:04:08 -0400 Subject: [PATCH 106/116] update Cargo.lock --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06fc7deeecac5..f63b3c7465074 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4740,7 +4740,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -4753,7 +4753,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -4764,7 +4764,7 @@ checksum = "2fb9865e03b9641e57448b9743915eadd0f642e41a41c4d9eaa8b5b861d887b0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -4775,7 +4775,7 @@ checksum = "68cf083ba5ba151ce3230a7c687cb5c890498adae59c85f3be7e8e741a6c9f65" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] From 7356072acc0c71b35092794007ebca67da7c791c Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 26 May 2023 12:10:49 +0200 Subject: [PATCH 107/116] cleaner example --- Cargo.lock | 1 - frame/examples/default-config/Cargo.toml | 3 +- frame/examples/default-config/src/lib.rs | 225 +++++++++++++++------ frame/examples/default-config/src/tests.rs | 147 -------------- frame/support/procedural/src/lib.rs | 204 ++++++++++--------- frame/system/src/lib.rs | 65 +++--- 6 files changed, 299 insertions(+), 346 deletions(-) delete mode 100644 frame/examples/default-config/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index f8d6397d9e10b..0f0e131218c88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6333,7 +6333,6 @@ dependencies = [ "frame-support", "frame-system", "log", - "pallet-balances", "parity-scale-codec", "scale-info", "sp-core", diff --git a/frame/examples/default-config/Cargo.toml b/frame/examples/default-config/Cargo.toml index 80c0134598474..09cc704686cce 100644 --- a/frame/examples/default-config/Cargo.toml +++ b/frame/examples/default-config/Cargo.toml @@ -18,7 +18,7 @@ log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } + sp-io = { version = "7.0.0", default-features = false, path = "../../../primitives/io" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } @@ -33,7 +33,6 @@ std = [ "frame-support/std", "frame-system/std", "log/std", - "pallet-balances/std", "scale-info/std", "sp-io/std", "sp-runtime/std", diff --git a/frame/examples/default-config/src/lib.rs b/frame/examples/default-config/src/lib.rs index 3a609e81a07c3..f75789a237c1c 100644 --- a/frame/examples/default-config/src/lib.rs +++ b/frame/examples/default-config/src/lib.rs @@ -18,93 +18,198 @@ //! //! # Default Config Pallet Example //! -//! A simple example of a FRAME pallet that utilizes [`frame_support::derive_impl`] to -//! implement a `DefaultConfig` for testing purposes. +//! A simple example of a FRAME pallet that utilizes [`frame_support::derive_impl`] to demonstrate +//! the simpler way to implement `Config` trait of pallets. This example only showcases this in a +//! `mock.rs` environment, but the same applies to a real runtime as well. //! //! See the source code for `tests.rs` to see the relevant //! [`derive_impl`](`frame_support::derive_impl`) example. //! -//! Note that this pallet makes use of `dev_mode` for ease of use, since the point of this -//! example is the tests, not the pallet itself. See `pallet-dev-mode` for a more detailed -//! example of the capabilities of `dev_mode`. +//! Note that this pallet makes use of `dev_mode` for ease of use, since the point of this example +//! is the tests, not the pallet itself. See `pallet-dev-mode` for a more detailed example of the +//! capabilities of `dev_mode`. // Ensure we're `no_std` when compiling for WASM. #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::dispatch::DispatchResult; -use frame_system::ensure_signed; - -// Re-export pallet items so that they can be accessed from the crate namespace. -pub use pallet::*; - -#[cfg(test)] -mod tests; - -/// A type alias for the balance type from this pallet's point of view. -type BalanceOf = ::Balance; - #[frame_support::pallet(dev_mode)] pub mod pallet { - use super::*; use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - #[pallet::config] - pub trait Config: pallet_balances::Config + frame_system::Config { - /// The overarching event type. + /// This pallet is annotated to have a default config. This will auto-generate + /// [`DefaultConfig`]. + #[pallet::config(with_default)] + pub trait Config: frame_system::Config { + /// The overarching event type. This is coming from the runtime, and cannot have a default. + /// In general, `Runtime*`-oriented types cannot have a sensible default. + #[pallet::no_default] type RuntimeEvent: From> + IsType<::RuntimeEvent>; - } - // Simple declaration of the `Pallet` type. It is placeholder we use to implement traits and - // method. - #[pallet::pallet] - pub struct Pallet(_); + /// An input parameter to this pallet. This value can have a default, because it is not + /// reliant on `frame_system::Config`. + type WithDefaultValue: Get; - #[pallet::call] - impl Pallet { - #[pallet::call_index(0)] - pub fn add_person(origin: OriginFor, id: T::AccountId) -> DispatchResult { - ensure_root(origin)?; + /// Same as [`Config::WithDefaultValue`], but we don't intend to define a default for this + /// in our tests below. + type OverwrittenDefaultValue: Get; - if let Some(mut people) = People::::get() { - people.push(id.clone()); - People::::set(Some(people)); - } else { - People::::set(Some(vec![id.clone()])); - } + /// An input parameter that relies on `::AccountId`. As of + /// now, such types cannot have defaults and need to be annotated as such: + #[pallet::no_default] + type CannotHaveDefault: Get; - // Let's deposit an event to let the outside world know this happened. - Self::deposit_event(Event::AddPeople { account: id }); + /// Something that is a normal type, with default. + type WithDefaultType; - Ok(()) - } + /// Same as [`Config::WithDefaultType`], but we don't intend to define a default for this + /// in our tests below. + type OverwrittenDefaultType; + } - #[pallet::call_index(1)] - pub fn set_points( - origin: OriginFor, - #[pallet::compact] new_value: T::Balance, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; + pub mod config_preludes { + // This will help use not need to disambiguate anything when using `derive_impl`. + use super::*; - // Put the new value into storage. - >::insert(&sender, new_value); + /// A type providing default configurations for this pallet in testing environment. + pub struct TestDefaultConfig; + #[frame_support::register_default_impl(TestDefaultConfig)] + impl DefaultConfig for TestDefaultConfig { + type WithDefaultValue = frame_support::traits::ConstU32<42>; + type OverwrittenDefaultValue = frame_support::traits::ConstU32<42>; - Self::deposit_event(Event::SetPoints { account: sender, balance: new_value }); + type WithDefaultType = u32; + type OverwrittenDefaultType = u32; + } - Ok(()) + /// A type providing default configurations for this pallet in a parachain environment. + pub struct ParachainDefaultConfig; + #[frame_support::register_default_impl(ParachainDefaultConfig)] + impl DefaultConfig for ParachainDefaultConfig { + type WithDefaultValue = frame_support::traits::ConstU32<66>; + type OverwrittenDefaultValue = frame_support::traits::ConstU32<66>; + type WithDefaultType = u32; + type OverwrittenDefaultType = u32; } } + #[pallet::pallet] + pub struct Pallet(_); + #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - AddPeople { account: T::AccountId }, - SetPoints { account: T::AccountId, balance: BalanceOf }, + pub enum Event {} +} + +#[cfg(any(test))] +pub mod tests { + use super::*; + + use frame_support::macro_magic::use_attr; + // Because `derive_impl` is a [macro_magic](https://crates.io/crates/macro_magic) attribute + // macro, [`#[use_attr]`](`frame_support::macro_magic::use_attr`) must be attached to any use + // statement that brings it into scope. + #[use_attr] + use frame_support::derive_impl; + + use super::pallet as pallet_default_config_example; + + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + type Block = frame_system::mocking::MockBlock; + + frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + DefaultPallet: pallet_default_config_example, + } + ); + + /// Normally this impl statement would need to have the areas that are commented out below be + /// specified manually. Attaching the `derive_impl` attribute, specifying + /// `frame_system::prelude::testing::TestDefaultConfig` as the `default_impl` and + /// `frame_system::pallet::DefaultConfig` as the `disambiguation_path` allows us to bring in + /// defaults for this impl from the `TestDefaultConfig` impl. + /// + /// This will fill in defaults for anything in the `default_impl` that isn't present in our + /// local impl, allowing us to override the `default_impl` in any cases where we want to be + /// explicit and differ from the `default_impl`. + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Test { + // these items are defined by frame-system as `no_default`, so we must specify them here. + // Note that these are types that actually rely on the outer runtime, and can't sensibly + // have an _independent_ default. + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type PalletInfo = PalletInfo; + type OnSetCode = (); + + // all of this is coming from `frame_system::config_preludes::TestDefaultConfig`. + + // type Index = u32; + // type BlockNumber = u32; + // type Header = sp_runtime::generic::Header; + // type Hash = sp_core::hash::H256; + // type Hashing = sp_runtime::traits::BlakeTwo256; + // type AccountId = u64; + // type Lookup = sp_runtime::traits::IdentityLookup; + // type BlockHashCount = frame_support::traits::ConstU32<10>; + // type MaxConsumers = frame_support::traits::ConstU32<16>; + // type AccountData = (); + // type OnNewAccount = (); + // type OnKilledAccount = (); + // type SystemWeightInfo = (); + // type SS58Prefix = (); + // type Version = (); + // type BlockWeights = (); + // type BlockLength = (); + // type DbWeight = (); + + // you could still overwrite any of them if desired. + type SS58Prefix = frame_support::traits::ConstU16<456>; } - #[pallet::storage] - pub type People = StorageValue<_, Vec>; + /// Similarly, we use the defaults provided by own crate as well. + use pallet::config_preludes::TestDefaultConfig; + #[derive_impl(TestDefaultConfig as pallet::DefaultConfig)] + impl crate::pallet::Config for Test { + // These two both cannot have defaults. + type RuntimeEvent = RuntimeEvent; + // Note that the default account-id type in + // `frame_system::config_preludes::TestDefaultConfig` is `u64`. + type CannotHaveDefault = frame_support::traits::ConstU64<1>; + + type OverwrittenDefaultValue = frame_support::traits::ConstU32<678>; + type OverwrittenDefaultType = u128; + } - #[pallet::storage] - pub type Points = StorageMap<_, _, T::AccountId, T::Balance>; + #[test] + fn it_works() { + use frame_support::traits::Get; + use pallet::{Config, DefaultConfig}; + + // assert one of the value types that is not overwritten. + assert_eq!( + <::WithDefaultValue as Get>::get(), + <::WithDefaultValue as Get>::get() + ); + + // assert one of the value types that is overwritten. + assert_eq!(<::OverwrittenDefaultValue as Get>::get(), 678u32); + + // assert one of the types that is not overwritten. + assert_eq!( + std::any::TypeId::of::<::WithDefaultType>(), + std::any::TypeId::of::<::WithDefaultType>() + ); + + // assert one of the types that is overwritten. + assert_eq!( + std::any::TypeId::of::<::OverwrittenDefaultType>(), + std::any::TypeId::of::() + ) + } } diff --git a/frame/examples/default-config/src/tests.rs b/frame/examples/default-config/src/tests.rs deleted file mode 100644 index 9f356e6688d1c..0000000000000 --- a/frame/examples/default-config/src/tests.rs +++ /dev/null @@ -1,147 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! This module tests the `pallet-default-config-example` and serves as a reference example for -//! how to use [`derive_impl`] to vastly simplify declaring a `Test` config. -//! -//! See the comments on line 49 for a detailed explanation. - -use crate::*; -use frame_support::{assert_ok, macro_magic::use_attr, traits::ConstU64}; -use sp_runtime::{testing::Header, BuildStorage}; - -// Because `derive_impl` is a [macro_magic](https://crates.io/crates/macro_magic) attribute -// macro, [`#[use_attr]`](`frame_support::macro_magic::use_attr`) must be attached to any use -// statement that brings it into scope. -#[use_attr] -use frame_support::derive_impl; - -// Reexport crate as its pallet name for construct_runtime. -use crate as pallet_default_config_example; - -type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlock; - -// For testing the pallet, we construct a mock runtime. -frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Example: pallet_default_config_example::{Pallet, Call, Storage, Event}, - } -); - -/// Normally this impl statement would need to have the areas that are commented out below -/// be specified manually. Attaching the `derive_impl` attribute, specifying -/// `frame_system::prelude::testing::TestDefaultConfig` as the `default_impl` and -/// `frame_system::pallet::DefaultConfig` as the `disambiguation_path` allows us to bring in -/// defaults for this impl from the `TestDefaultConfig` impl. This will fill in defaults for -/// anything in the `default_impl` that isn't present in our local impl, allowing us to -/// override the `default_impl` in any cases where we want to be explicit and differ from the -/// `default_impl`. -#[derive_impl(frame_system::prelude::testing::TestDefaultConfig as frame_system::pallet::DefaultConfig)] -impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - // type BlockWeights = (); - // type BlockLength = (); - // type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - // type Index = u64; - type BlockNumber = u64; - // type Hash = sp_core::H256; - type RuntimeCall = RuntimeCall; - // type Hashing = BlakeTwo256; - // type AccountId = u64; - // type Lookup = IdentityLookup; - type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - // type Version = (); - type PalletInfo = PalletInfo; - - /// we override `AccountData`, since we want a u64 not a u32. - type AccountData = pallet_balances::AccountData; - - // type OnNewAccount = (); - // type OnKilledAccount = (); - // type SystemWeightInfo = (); - // type SS58Prefix = (); - type OnSetCode = (); - // type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -impl pallet_balances::Config for Test { - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type Balance = u64; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ConstU64<1>; - type AccountStore = System; - type WeightInfo = (); - type FreezeIdentifier = (); - type MaxFreezes = (); - type HoldIdentifier = (); - type MaxHolds = (); -} - -impl Config for Test { - type RuntimeEvent = RuntimeEvent; -} - -// This function basically just builds a genesis storage key/value store according to -// our desired mockup. -pub fn new_test_ext() -> sp_io::TestExternalities { - let t = GenesisConfig { - // We use default for brevity, but you can configure as desired if needed. - system: Default::default(), - balances: Default::default(), - } - .build_storage() - .unwrap(); - t.into() -} - -#[test] -fn it_works_for_optional_value() { - new_test_ext().execute_with(|| { - assert_eq!(People::::get(), None); - - let val1 = 42; - assert_ok!(Example::add_person(RuntimeOrigin::root(), val1)); - assert_eq!(People::::get(), Some(vec![val1])); - - // Check that accumulate works when we have Some value in People already. - let val2 = 27; - assert_ok!(Example::add_person(RuntimeOrigin::root(), val2)); - assert_eq!(People::::get(), Some(vec![val1, val2])); - }); -} - -#[test] -fn set_person_works() { - new_test_ext().execute_with(|| { - let test_val = 133; - assert_ok!(Example::set_points(RuntimeOrigin::signed(1), test_val.into())); - assert_eq!(Points::::get(1), Some(test_val)); - }); -} diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index ab870f2136218..84a8b37f92e06 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -780,9 +780,8 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { .into() } -/// This attribute can be used to derive a full implementation of a trait based on a local -/// partial impl and an external impl containing defaults that can be overriden in the local -/// impl. +/// This attribute can be used to derive a full implementation of a trait based on a local partial +/// impl and an external impl containing defaults that can be overriden in the local impl. /// /// For a full end-to-end example, see [below](#use-case-auto-derive-test-pallet-config-traits). /// @@ -791,10 +790,9 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// The attribute should be attached to an impl block (strictly speaking a `syn::ItemImpl`) for /// which we want to inject defaults in the event of missing trait items in the block. /// -/// The attribute minimally takes a single `default_impl_path` argument, which should be the -/// module path to an impl registered via -/// [`#[register_default_impl]`](`macro@register_default_impl`) that contains the default trait -/// items we want to potentially inject, with the general form: +/// The attribute minimally takes a single `default_impl_path` argument, which should be the module +/// path to an impl registered via [`#[register_default_impl]`](`macro@register_default_impl`) that +/// contains the default trait items we want to potentially inject, with the general form: /// /// ```ignore /// #[derive_impl(default_impl_path)] @@ -803,32 +801,31 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// } /// ``` /// -/// Optionally, a `disambiguation_path` can be specified as follows by providing `as -/// path::here` after the `default_impl_path`: +/// Optionally, a `disambiguation_path` can be specified as follows by providing `as path::here` +/// after the `default_impl_path`: /// /// ```ignore /// #[derive_impl(default_impl_path as disambiguation_path)] /// impl SomeTrait for SomeStruct { -/// ... +/// ... /// } /// ``` /// /// The `disambiguation_path`, if specified, should be the path to a trait that will be used to /// qualify all default entries that are injected into the local impl. For example if your -/// `default_impl_path` is `some::path::TestTrait` and your `disambiguation_path` is +/// `default_impl_path` is `some::path::TestTraitImpl` and your `disambiguation_path` is /// `another::path::DefaultTrait`, any items injected into the local impl will be qualified as -/// `::specific_trait_item`. +/// `::specific_trait_item`. /// /// If you omit the `as disambiguation_path` portion, the `disambiguation_path` will internally -/// default to `A` from the `impl A for B` part of the default impl. This is useful for -/// scenarios where all of the relevant types are already in scope via `use` statements. +/// default to `A` from the `impl A for B` part of the default impl. This is useful for scenarios +/// where all of the relevant types are already in scope via `use` statements. /// /// Conversely, the `default_impl_path` argument is required and cannot be omitted. /// -/// You can also make use of `#[pallet::no_default]` on specific items in your default impl -/// that you want to ensure will not be copied over but that you nonetheless want to use -/// locally in the context of the foreign impl and the pallet (or context) in which it is -/// defined. +/// You can also make use of `#[pallet::no_default]` on specific items in your default impl that you +/// want to ensure will not be copied over but that you nonetheless want to use locally in the +/// context of the foreign impl and the pallet (or context) in which it is defined. /// /// ## Use-Case Example: Auto-Derive Test Pallet Config Traits /// @@ -840,25 +837,25 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// In this case, the `#[derive_impl(..)]` attribute should be attached to an `impl` block that /// implements a compatible `Config` such as `frame_system::Config` for a test/mock runtime, and /// should receive as its first argument the path to a `DefaultConfig` impl that has been registered -/// via [`#[register_default_impl]`](`macro@register_default_impl`), and as its second argument, -/// the path to the auto-generated `DefaultConfig` for the existing pallet `Config` we want to -/// base our test config off of. +/// via [`#[register_default_impl]`](`macro@register_default_impl`), and as its second argument, the +/// path to the auto-generated `DefaultConfig` for the existing pallet `Config` we want to base our +/// test config off of. /// /// The following is what the `basic` example pallet would look like with a default testing config: /// /// ```ignore -/// #[derive_impl(frame_system::prelude::testing::TestDefaultConfig as frame_system::pallet::DefaultConfig)] +/// #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::pallet::DefaultConfig)] /// impl frame_system::Config for Test { -/// // These are all defined by system as mandatory. -/// type BaseCallFilter = frame_support::traits::Everything; -/// type RuntimeEvent = RuntimeEvent; -/// type RuntimeCall = RuntimeCall; -/// type RuntimeOrigin = RuntimeOrigin; -/// type OnSetCode = (); -/// type PalletInfo = PalletInfo; -/// type Header = Header; -/// // We decide to override this one. -/// type AccountData = pallet_balances::AccountData; +/// // These are all defined by system as mandatory. +/// type BaseCallFilter = frame_support::traits::Everything; +/// type RuntimeEvent = RuntimeEvent; +/// type RuntimeCall = RuntimeCall; +/// type RuntimeOrigin = RuntimeOrigin; +/// type OnSetCode = (); +/// type PalletInfo = PalletInfo; +/// type Header = Header; +/// // We decide to override this one. +/// type AccountData = pallet_balances::AccountData; /// } /// ``` /// @@ -869,23 +866,23 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// /// #[register_default_impl(TestDefaultConfig)] /// impl DefaultConfig for TestDefaultConfig { -/// type Version = (); -/// type BlockWeights = (); -/// type BlockLength = (); -/// type DbWeight = (); -/// type Index = u64; -/// type BlockNumber = u64; -/// type Hash = sp_core::hash::H256; -/// type Hashing = sp_runtime::traits::BlakeTwo256; -/// type AccountId = AccountId; -/// type Lookup = IdentityLookup; -/// type BlockHashCount = frame_support::traits::ConstU64<10>; -/// type AccountData = u32; -/// type OnNewAccount = (); -/// type OnKilledAccount = (); -/// type SystemWeightInfo = (); -/// type SS58Prefix = (); -/// type MaxConsumers = frame_support::traits::ConstU32<16>; +/// type Version = (); +/// type BlockWeights = (); +/// type BlockLength = (); +/// type DbWeight = (); +/// type Index = u64; +/// type BlockNumber = u64; +/// type Hash = sp_core::hash::H256; +/// type Hashing = sp_runtime::traits::BlakeTwo256; +/// type AccountId = AccountId; +/// type Lookup = IdentityLookup; +/// type BlockHashCount = frame_support::traits::ConstU64<10>; +/// type AccountData = u32; +/// type OnNewAccount = (); +/// type OnKilledAccount = (); +/// type SystemWeightInfo = (); +/// type SS58Prefix = (); +/// type MaxConsumers = frame_support::traits::ConstU32<16>; /// } /// ``` /// @@ -893,68 +890,75 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// /// ```ignore /// impl frame_system::Config for Test { -/// use frame_system::prelude::testing::TestDefaultConfig; -/// use frame_system::pallet::DefaultConfig; -/// -/// type BaseCallFilter = frame_support::traits::Everything; -/// type RuntimeEvent = RuntimeEvent; -/// type RuntimeCall = RuntimeCall; -/// type RuntimeOrigin = RuntimeOrigin; -/// type OnSetCode = (); -/// type PalletInfo = PalletInfo; -/// type Header = Header; -/// type AccountData = pallet_balances::AccountData; -/// type Version = ::Version; -/// type BlockWeights = ::BlockWeights; -/// type BlockLength = ::BlockLength; -/// type DbWeight = ::DbWeight; -/// type Index = ::Index; -/// type BlockNumber = ::BlockNumber; -/// type Hash = ::Hash; -/// type Hashing = ::Hashing; -/// type AccountId = ::AccountId; -/// type Lookup = ::Lookup; -/// type BlockHashCount = ::BlockHashCount; -/// type OnNewAccount = ::OnNewAccount; -/// type OnKilledAccount = ::OnKilledAccount; -/// type SystemWeightInfo = ::SystemWeightInfo; -/// type SS58Prefix = ::SS58Prefix; -/// type MaxConsumers = ::MaxConsumers; +/// use frame_system::config_preludes::TestDefaultConfig; +/// use frame_system::pallet::DefaultConfig; +/// +/// type BaseCallFilter = frame_support::traits::Everything; +/// type RuntimeEvent = RuntimeEvent; +/// type RuntimeCall = RuntimeCall; +/// type RuntimeOrigin = RuntimeOrigin; +/// type OnSetCode = (); +/// type PalletInfo = PalletInfo; +/// type Header = Header; +/// type AccountData = pallet_balances::AccountData; +/// type Version = ::Version; +/// type BlockWeights = ::BlockWeights; +/// type BlockLength = ::BlockLength; +/// type DbWeight = ::DbWeight; +/// type Index = ::Index; +/// type BlockNumber = ::BlockNumber; +/// type Hash = ::Hash; +/// type Hashing = ::Hashing; +/// type AccountId = ::AccountId; +/// type Lookup = ::Lookup; +/// type BlockHashCount = ::BlockHashCount; +/// type OnNewAccount = ::OnNewAccount; +/// type OnKilledAccount = ::OnKilledAccount; +/// type SystemWeightInfo = ::SystemWeightInfo; +/// type SS58Prefix = ::SS58Prefix; +/// type MaxConsumers = ::MaxConsumers; /// } /// ``` /// /// You can then use the resulting `Test` config in test scenarios. /// -/// Note that items that are _not_ present in our local `DefaultConfig` are automatically -/// copied from the foreign trait (in this case `TestDefaultConfig`) into the local trait impl -/// (in this case `Test`), unless the trait item in the local trait impl is marked with -/// [`#[pallet::no_default]`](`macro@no_default`), in which case it cannot be overridden, and -/// any attempts to do so will result in a compiler error. +/// Note that items that are _not_ present in our local `DefaultConfig` are automatically copied +/// from the foreign trait (in this case `TestDefaultConfig`) into the local trait impl (in this +/// case `Test`), unless the trait item in the local trait impl is marked with +/// [`#[pallet::no_default]`](`macro@no_default`), in which case it cannot be overridden, and any +/// attempts to do so will result in a compiler error. /// -/// See `frame/examples/default-config/tests.rs` for a runnable end-to-end example pallet that -/// makes use of `derive_impl` to derive its testing config. +/// See `frame/examples/default-config/tests.rs` for a runnable end-to-end example pallet that makes +/// use of `derive_impl` to derive its testing config. /// /// See [here](`macro@config`) for more information and caveats about the auto-generated /// `DefaultConfig` trait. /// /// ## Optional Conventions /// -/// Note that as an optional convention, we encourage creating a `prelude` module inside of -/// your pallet with sub-modules for `testing`, `production` etc.. This is the convention we -/// follow for `frame_system`'s `TestDefaultConfig` which, as shown above, is located at -/// `frame_system::prelude::testing::TestDefaultConfig`. This is just a suggested convention -- -/// there is nothing in the code that expects modules with these names to be in place, so there -/// is no imperative to follow this pattern unless desired. +/// Note that as an optional convention, we encourage creating a `config_preludes` module inside of +/// your pallet. This is the convention we follow for `frame_system`'s `TestDefaultConfig` which, as +/// shown above, is located at `frame_system::config_preludes::TestDefaultConfig`. This is just a +/// suggested convention -- there is nothing in the code that expects modules with these names to be +/// in place, so there is no imperative to follow this pattern unless desired. +/// +/// In `config_preludes`, you can place types named like: +/// +/// * `TestDefaultConfig` +/// * `ParachainDefaultConfig` +/// * `SolochainDefaultConfig` +/// +/// Signifying in which context they can be used. /// /// # Advanced Usage /// /// ## Importing & Re-Exporting /// /// Since `#[derive_impl(..)]` is a -/// [`macro_magic`](https://docs.rs/macro_magic/latest/macro_magic/)-based attribute macro, -/// special care must be taken when importing and re-exporting it. Glob imports will work -/// properly, such as `use frame_support::*` to bring `derive_impl` into scope, however any -/// other use statements involving `derive_impl` should have +/// [`macro_magic`](https://docs.rs/macro_magic/latest/macro_magic/)-based attribute macro, special +/// care must be taken when importing and re-exporting it. Glob imports will work properly, such as +/// `use frame_support::*` to bring `derive_impl` into scope, however any other use statements +/// involving `derive_impl` should have /// [`#[macro_magic::use_attr]`](https://docs.rs/macro_magic/latest/macro_magic/attr.use_attr.html) /// attached or your use statement will fail to fully bring the macro into scope. /// @@ -973,16 +977,16 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { /// ## Expansion /// /// The `#[derive_impl(default_impl_path as disambiguation_path)]` attribute will expand to the -/// local impl, with any extra items from the foreign impl that aren't present in the local -/// impl also included. In the case of a colliding trait item, the version of the item that -/// exists in the local impl will be retained. All imported items are qualified by the -/// `disambiguation_path`, as discussed above. +/// local impl, with any extra items from the foreign impl that aren't present in the local impl +/// also included. In the case of a colliding trait item, the version of the item that exists in the +/// local impl will be retained. All imported items are qualified by the `disambiguation_path`, as +/// discussed above. /// /// ## Handling of Unnamed Trait Items /// -/// Items that lack a `syn::Ident` for whatever reason are first checked to see if they -/// exist, verbatim, in the local/destination trait before they are copied over, so you should -/// not need to worry about collisions between identical unnamed items. +/// Items that lack a `syn::Ident` for whatever reason are first checked to see if they exist, +/// verbatim, in the local/destination trait before they are copied over, so you should not need to +/// worry about collisions between identical unnamed items. #[import_tokens_attr(frame_support::macro_magic)] #[with_custom_parsing(derive_impl::DeriveImplAttrArgs)] #[proc_macro_attribute] diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 1856881d00df1..8c717e3f5eb12 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -202,43 +202,37 @@ pub mod pallet { use frame_support::pallet_prelude::*; /// Contains default types suitable for various environments - pub mod prelude { - use super::*; + pub mod config_preludes { + use super::DefaultConfig; - /// Contains default types suitable for testing purposes - pub mod testing { + /// Provides a viable default config that can be used with + /// [`derive_impl`](`frame_support::derive_impl`) to derive a testing pallet config + /// based on this one. + /// + /// See `Test` in the `default-config` example pallet's `test.rs` for an example of + /// a downstream user of this particular `TestDefaultConfig` + pub struct TestDefaultConfig; + + #[frame_support::register_default_impl(TestDefaultConfig)] + impl DefaultConfig for TestDefaultConfig { + type Index = u32; + type BlockNumber = u32; + type Header = sp_runtime::generic::Header; + type Hash = sp_core::hash::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; - use super::*; - use sp_runtime::traits::IdentityLookup; - - /// Provides a viable default config that can be used with - /// [`derive_impl`](`frame_support::derive_impl`) to derive a testing pallet config - /// based on this one. - /// - /// See `Test` in the `default-config` example pallet's `test.rs` for an example of - /// a downstream user of this particular `TestDefaultConfig` - pub struct TestDefaultConfig; - - #[register_default_impl(TestDefaultConfig)] - impl DefaultConfig for TestDefaultConfig { - type Version = (); - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type Index = u64; - type BlockNumber = u32; - type Hash = sp_core::hash::H256; - type Hashing = sp_runtime::traits::BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type BlockHashCount = frame_support::traits::ConstU32<10>; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } + type Lookup = sp_runtime::traits::IdentityLookup; + type BlockHashCount = frame_support::traits::ConstU32<10>; + type MaxConsumers = frame_support::traits::ConstU32<16>; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type Version = (); + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); } } @@ -344,7 +338,6 @@ pub mod pallet { type Lookup: StaticLookup; /// The block header. - #[pallet::no_default] type Header: Parameter + traits::Header; /// Maximum number of block number to block hash mappings to keep (oldest pruned first). From 85f20d0374d985f25d263faf57fccca1e7e907c6 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 26 May 2023 13:50:56 +0200 Subject: [PATCH 108/116] tweaks --- frame/examples/default-config/src/lib.rs | 1 - .../support/procedural/src/pallet/parse/config.rs | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/frame/examples/default-config/src/lib.rs b/frame/examples/default-config/src/lib.rs index f75789a237c1c..243c9db9dad12 100644 --- a/frame/examples/default-config/src/lib.rs +++ b/frame/examples/default-config/src/lib.rs @@ -15,7 +15,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! //! # Default Config Pallet Example //! //! A simple example of a FRAME pallet that utilizes [`frame_support::derive_impl`] to demonstrate diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index d538c7f999952..10cc407836f76 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -343,10 +343,10 @@ impl ConfigDef { let mut consts_metadata = vec![]; let mut default_sub_trait = vec![]; for trait_item in &mut item.items { - // Parse for event let is_event = check_event_type(frame_system, trait_item, has_instance)?; - let mut no_default = false; has_event_type = has_event_type || is_event; + + let mut already_no_default = false; let mut already_constant = false; while let Ok(Some(pallet_attr)) = @@ -366,8 +366,7 @@ impl ConfigDef { (PalletAttrType::Constant(_), _) => return Err(syn::Error::new( trait_item.span(), - "Invalid pallet::constant in pallet::config, expected \ - type trait item", + "Invalid #[pallet::constant] in #[pallet::config], expected type item", )), (PalletAttrType::NoDefault(_), _) => { if !enable_default { @@ -377,18 +376,18 @@ impl ConfigDef { has been specified" )) } - if no_default { + if already_no_default { return Err(syn::Error::new( pallet_attr._bracket.span.join(), - "Duplicate #[pallet::no_default] attribute not allowed.", + "Duplicate #[pallet::already_no_default] attribute not allowed.", )) } - no_default = true; + already_no_default = true; }, } } - if !no_default && !is_event && enable_default { + if !already_no_default && !is_event && enable_default { default_sub_trait.push(trait_item.clone()); } } From 19540f6f5f44a406f3bf465acd27545d4aafdfda Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 26 May 2023 14:02:24 +0200 Subject: [PATCH 109/116] update docs more --- frame/examples/default-config/src/lib.rs | 29 ++++++++++-------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/frame/examples/default-config/src/lib.rs b/frame/examples/default-config/src/lib.rs index 243c9db9dad12..d3d8447ea85f5 100644 --- a/frame/examples/default-config/src/lib.rs +++ b/frame/examples/default-config/src/lib.rs @@ -21,27 +21,31 @@ //! the simpler way to implement `Config` trait of pallets. This example only showcases this in a //! `mock.rs` environment, but the same applies to a real runtime as well. //! -//! See the source code for `tests.rs` to see the relevant -//! [`derive_impl`](`frame_support::derive_impl`) example. +//! See the source code of [`tests`] for a real examples. //! -//! Note that this pallet makes use of `dev_mode` for ease of use, since the point of this example -//! is the tests, not the pallet itself. See `pallet-dev-mode` for a more detailed example of the -//! capabilities of `dev_mode`. +//! Study the following types: +//! +//! - [`pallet::DefaultConfig`], and how it differs from [`pallet::Config`]. +//! - [`pallet::config_preludes::TestDefaultConfig`] and how it implements +//! [`pallet::DefaultConfig`]. +//! - Notice how [`pallet::DefaultConfig`] is independent of [`frame_system::Config`]. // Ensure we're `no_std` when compiling for WASM. #![cfg_attr(not(feature = "std"), no_std)] -#[frame_support::pallet(dev_mode)] +#[frame_support::pallet] pub mod pallet { use frame_support::pallet_prelude::*; /// This pallet is annotated to have a default config. This will auto-generate /// [`DefaultConfig`]. + /// + /// It will be an identical, but won't have anything that is `#[pallet::no_default]`. #[pallet::config(with_default)] pub trait Config: frame_system::Config { /// The overarching event type. This is coming from the runtime, and cannot have a default. /// In general, `Runtime*`-oriented types cannot have a sensible default. - #[pallet::no_default] + #[pallet::no_default] // optional. `RuntimeEvent` is automatically excluded as well. type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// An input parameter to this pallet. This value can have a default, because it is not @@ -98,7 +102,7 @@ pub mod pallet { pub enum Event {} } -#[cfg(any(test))] +#[cfg(any(test, doc))] pub mod tests { use super::*; @@ -125,15 +129,6 @@ pub mod tests { } ); - /// Normally this impl statement would need to have the areas that are commented out below be - /// specified manually. Attaching the `derive_impl` attribute, specifying - /// `frame_system::prelude::testing::TestDefaultConfig` as the `default_impl` and - /// `frame_system::pallet::DefaultConfig` as the `disambiguation_path` allows us to bring in - /// defaults for this impl from the `TestDefaultConfig` impl. - /// - /// This will fill in defaults for anything in the `default_impl` that isn't present in our - /// local impl, allowing us to override the `default_impl` in any cases where we want to be - /// explicit and differ from the `default_impl`. #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { // these items are defined by frame-system as `no_default`, so we must specify them here. From b36a0864e5e3d64713819d1c38f43b66c344acc2 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 26 May 2023 14:06:45 +0200 Subject: [PATCH 110/116] update docs more --- frame/examples/default-config/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/examples/default-config/src/lib.rs b/frame/examples/default-config/src/lib.rs index d3d8447ea85f5..a2597a8bf33d2 100644 --- a/frame/examples/default-config/src/lib.rs +++ b/frame/examples/default-config/src/lib.rs @@ -69,6 +69,7 @@ pub mod pallet { type OverwrittenDefaultType; } + /// Container for different types that implement [`DefaultConfig`]` of this pallet. pub mod config_preludes { // This will help use not need to disambiguate anything when using `derive_impl`. use super::*; From 68b76d2526ff806ef69474177c74f1b71293036a Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 26 May 2023 14:07:08 +0200 Subject: [PATCH 111/116] update docs more --- frame/examples/default-config/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/examples/default-config/src/lib.rs b/frame/examples/default-config/src/lib.rs index a2597a8bf33d2..a01fda34f3035 100644 --- a/frame/examples/default-config/src/lib.rs +++ b/frame/examples/default-config/src/lib.rs @@ -30,7 +30,6 @@ //! [`pallet::DefaultConfig`]. //! - Notice how [`pallet::DefaultConfig`] is independent of [`frame_system::Config`]. -// Ensure we're `no_std` when compiling for WASM. #![cfg_attr(not(feature = "std"), no_std)] #[frame_support::pallet] From 298352bd440aa27c53f640cd81c30a5d6129dae4 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 26 May 2023 14:08:54 +0200 Subject: [PATCH 112/116] update docs more --- frame/examples/default-config/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frame/examples/default-config/src/lib.rs b/frame/examples/default-config/src/lib.rs index a01fda34f3035..adb2469e92fd9 100644 --- a/frame/examples/default-config/src/lib.rs +++ b/frame/examples/default-config/src/lib.rs @@ -48,7 +48,7 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// An input parameter to this pallet. This value can have a default, because it is not - /// reliant on `frame_system::Config`. + /// reliant on `frame_system::Config` or the overarching runtime in any way. type WithDefaultValue: Get; /// Same as [`Config::WithDefaultValue`], but we don't intend to define a default for this @@ -56,7 +56,8 @@ pub mod pallet { type OverwrittenDefaultValue: Get; /// An input parameter that relies on `::AccountId`. As of - /// now, such types cannot have defaults and need to be annotated as such: + /// now, such types cannot have defaults and need to be annotated as such, iff + /// `#[pallet::config(with_default)]` is enabled: #[pallet::no_default] type CannotHaveDefault: Get; @@ -166,7 +167,7 @@ pub mod tests { type SS58Prefix = frame_support::traits::ConstU16<456>; } - /// Similarly, we use the defaults provided by own crate as well. + // Similarly, we use the defaults provided by own crate as well. use pallet::config_preludes::TestDefaultConfig; #[derive_impl(TestDefaultConfig as pallet::DefaultConfig)] impl crate::pallet::Config for Test { From e141483659f5b3444b6fc7d60dd4a2238a54e128 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sun, 28 May 2023 10:32:43 +0200 Subject: [PATCH 113/116] fix ui tests --- frame/support/procedural/src/pallet/parse/config.rs | 2 +- frame/support/test/tests/pallet_ui.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 10cc407836f76..6a3693a3ab0f2 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -379,7 +379,7 @@ impl ConfigDef { if already_no_default { return Err(syn::Error::new( pallet_attr._bracket.span.join(), - "Duplicate #[pallet::already_no_default] attribute not allowed.", + "Duplicate #[pallet::no_default] attribute not allowed.", )) } already_no_default = true; diff --git a/frame/support/test/tests/pallet_ui.rs b/frame/support/test/tests/pallet_ui.rs index 466957c9faa63..f5a9912692f43 100644 --- a/frame/support/test/tests/pallet_ui.rs +++ b/frame/support/test/tests/pallet_ui.rs @@ -31,6 +31,6 @@ fn pallet_ui() { std::env::set_var("RUSTFLAGS", "--deny warnings"); let t = trybuild::TestCases::new(); - t.compile_fail("tests/pallet_ui/*.rs"); + t.compile_fail("tests/pallet_ui/.rs"); t.pass("tests/pallet_ui/pass/*.rs"); } From 4b6fe4a4f41fd647fb0932d09d849f2b1e91c2a3 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sun, 28 May 2023 10:41:36 +0200 Subject: [PATCH 114/116] err --- frame/support/test/tests/pallet_ui.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/test/tests/pallet_ui.rs b/frame/support/test/tests/pallet_ui.rs index f5a9912692f43..30bd21f4b4ba5 100644 --- a/frame/support/test/tests/pallet_ui.rs +++ b/frame/support/test/tests/pallet_ui.rs @@ -31,6 +31,6 @@ fn pallet_ui() { std::env::set_var("RUSTFLAGS", "--deny warnings"); let t = trybuild::TestCases::new(); - t.compile_fail("tests/pallet_ui/.rs"); + t.compile_fail("tests/pallet_ui/* */.rs"); t.pass("tests/pallet_ui/pass/*.rs"); } From 9ee1b096d1e906fb2edd15e66ac673912ae74bdf Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 29 May 2023 19:58:31 +0200 Subject: [PATCH 115/116] Update frame/support/test/tests/pallet_ui.rs --- frame/support/test/tests/pallet_ui.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/test/tests/pallet_ui.rs b/frame/support/test/tests/pallet_ui.rs index 30bd21f4b4ba5..466957c9faa63 100644 --- a/frame/support/test/tests/pallet_ui.rs +++ b/frame/support/test/tests/pallet_ui.rs @@ -31,6 +31,6 @@ fn pallet_ui() { std::env::set_var("RUSTFLAGS", "--deny warnings"); let t = trybuild::TestCases::new(); - t.compile_fail("tests/pallet_ui/* */.rs"); + t.compile_fail("tests/pallet_ui/*.rs"); t.pass("tests/pallet_ui/pass/*.rs"); } From 638c1fa3d97bb2af697f50e9d12278f388bee735 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Mon, 29 May 2023 20:40:03 +0200 Subject: [PATCH 116/116] update ui tests --- frame/support/test/tests/pallet_ui/trait_invalid_item.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/support/test/tests/pallet_ui/trait_invalid_item.stderr b/frame/support/test/tests/pallet_ui/trait_invalid_item.stderr index 72495d94b3079..e3409a819114a 100644 --- a/frame/support/test/tests/pallet_ui/trait_invalid_item.stderr +++ b/frame/support/test/tests/pallet_ui/trait_invalid_item.stderr @@ -1,5 +1,5 @@ -error: Invalid pallet::constant in pallet::config, expected type trait item - --> $DIR/trait_invalid_item.rs:9:3 +error: Invalid #[pallet::constant] in #[pallet::config], expected type item + --> tests/pallet_ui/trait_invalid_item.rs:9:3 | 9 | const U: u8 = 3; | ^^^^^