diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index e2567d0477585..c4f10227a5e9e 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -1028,7 +1028,7 @@ mod tests { use hex_literal::hex; use sp_core::H256; use sp_runtime::{ - Perbill, traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, testing::Header, + Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header, BuildStorage, }; use crate as collective; diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index c59ac590316de..91fd3fab6e0aa 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -1092,7 +1092,7 @@ mod tests { use sp_core::H256; use sp_runtime::{ Perbill, testing::Header, BuildStorage, DispatchResult, - traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, + traits::{BlakeTwo256, IdentityLookup}, }; use crate as elections_phragmen; diff --git a/frame/elections/src/mock.rs b/frame/elections/src/mock.rs index c9b2523c4bc8a..9f20b8b9ace6e 100644 --- a/frame/elections/src/mock.rs +++ b/frame/elections/src/mock.rs @@ -27,7 +27,7 @@ use frame_support::{ }; use sp_core::H256; use sp_runtime::{ - Perbill, BuildStorage, testing::Header, traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, + Perbill, BuildStorage, testing::Header, traits::{BlakeTwo256, IdentityLookup}, }; use crate as elections; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index ad6e8a14d5622..95496726c8dcd 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -27,7 +27,7 @@ use frame_support::{ use frame_system as system; use sp_runtime::{ SaturatedConversion, - traits::{IdentityLookup, Block as BlockT}, + traits::IdentityLookup, testing::{Header, UintAuthorityId}, }; diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 57827b0673916..1b43a33032f12 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -19,22 +19,79 @@ mod parse; use frame_support_procedural_tools::syn_ext as ext; use frame_support_procedural_tools::{generate_crate_access, generate_hidden_includes}; -use parse::{ModuleDeclaration, RuntimeDefinition, WhereSection}; +use parse::{RuntimeDefinition, WhereSection, ExpandedModuleDeclaration}; use proc_macro::TokenStream; -use proc_macro2::TokenStream as TokenStream2; -use quote::quote; +use proc_macro2::{TokenStream as TokenStream2, Span}; +use quote::{quote, quote_spanned}; use syn::{Ident, Result, TypePath}; +use core::convert::TryFrom; /// The fixed name of the system module. const SYSTEM_MODULE_NAME: &str = "System"; pub fn construct_runtime(input: TokenStream) -> TokenStream { + let input_clone = input.clone().into(); let definition = syn::parse_macro_input!(input as RuntimeDefinition); + + if let Some(preprocess) = construct_runtime_preprocess(&definition, input_clone) + .unwrap_or_else(|e| Some(e.to_compile_error())) + { + return preprocess.into() + } + construct_runtime_parsed(definition) .unwrap_or_else(|e| e.to_compile_error()) .into() } +/// Module define with `MyModule: mymodule` expand to their full definition +/// `MyModule: mymodule::{..}` by calling `mymodule::construct_runtime_args!` +fn construct_runtime_preprocess( + def: &RuntimeDefinition, + input: TokenStream2, +) -> Result> { + let mut auto_modules = vec![]; + for module in def.modules.content.inner.iter() { + if module.module_parts.is_none() { + auto_modules.push(module.clone()) + } + } + + if !auto_modules.is_empty() { + + // Make frame-support available to construct_runtime_args + let hidden_crate_name = "construct_runtime_preprocess"; + let scrate_decl = generate_hidden_includes(&hidden_crate_name, "frame-support"); + let scrate = generate_crate_access(&hidden_crate_name, "frame-support"); + + let mut expand = quote!( #scrate::construct_runtime! { #input } ); + + while let Some(module) = auto_modules.pop() { + let module_name = &module.name; + let module_module = &module.module; + let module_instance = module.instance.as_ref() + .map(|instance| quote!( ::< #instance > )); + + expand = quote_spanned!(module_name.span() => + #module_module::construct_runtime_args! { + { #module_name : #module_module #module_instance} + #expand + } + ); + } + + expand = quote!( + #scrate_decl + #expand + ); + + Ok(Some(expand)) + } else { + Ok(None) + } +} + +/// All module must have been expanded, i.e. as `MyModule: mymodule::{...}` fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result { let RuntimeDefinition { name, @@ -52,6 +109,15 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result = modules.into_iter() + .map(TryFrom::try_from) + .collect::>() + .map_err(|_| syn::Error::new( + Span::call_site(), + "Internal Error: all module must be expanded" + ))?; + // Assert we have system module declared let system_module = match find_system_module(modules.iter()) { Some(sm) => sm, @@ -77,7 +143,7 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result Result( runtime: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, scrate: &'a TokenStream2, ) -> TokenStream2 { let modules_tokens = module_declarations @@ -152,7 +218,7 @@ fn decl_validate_unsigned<'a>( fn decl_outer_inherent<'a>( block: &'a syn::TypePath, unchecked_extrinsic: &'a syn::TypePath, - module_declarations: impl Iterator, + module_declarations: impl Iterator, scrate: &'a TokenStream2, ) -> TokenStream2 { let modules_tokens = module_declarations.filter_map(|module_declaration| { @@ -163,6 +229,12 @@ fn decl_outer_inherent<'a>( }) }); quote!( + // Prevent UncheckedExtrinsic to print unused warning. + const _: () = { + #[allow(unused)] + type __hidden_use_unchecked_extrinsic = #unchecked_extrinsic; + }; + #scrate::impl_outer_inherent!( impl Inherents where Block = #block, @@ -176,7 +248,7 @@ fn decl_outer_inherent<'a>( fn decl_outer_config<'a>( runtime: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, scrate: &'a TokenStream2, ) -> TokenStream2 { let modules_tokens = module_declarations @@ -203,8 +275,16 @@ fn decl_outer_config<'a>( #module #(#instance)* #(#generics)*, ) }); + + // If caller doesn't depends on serde, then serde must be provided manually. + let hidden_serde_use = syn::LitStr::new( + &format!("{}::serde", scrate), + proc_macro2::Span::call_site(), + ); + quote!( #scrate::sp_runtime::impl_outer_config! { + serde_crate { #hidden_serde_use } pub struct GenesisConfig for #runtime { #(#modules_tokens)* } @@ -214,7 +294,7 @@ fn decl_outer_config<'a>( fn decl_runtime_metadata<'a>( runtime: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, scrate: &'a TokenStream2, extrinsic: &TypePath, ) -> TokenStream2 { @@ -250,7 +330,7 @@ fn decl_runtime_metadata<'a>( fn decl_outer_dispatch<'a>( runtime: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, scrate: &'a TokenStream2, ) -> TokenStream2 { let modules_tokens = module_declarations @@ -271,7 +351,7 @@ fn decl_outer_dispatch<'a>( fn decl_outer_origin<'a>( runtime_name: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, system_name: &'a Ident, scrate: &'a TokenStream2, ) -> syn::Result { @@ -308,7 +388,7 @@ fn decl_outer_origin<'a>( fn decl_outer_event<'a>( runtime_name: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, scrate: &'a TokenStream2, ) -> syn::Result { let mut modules_tokens = TokenStream2::new(); @@ -344,7 +424,7 @@ fn decl_outer_event<'a>( fn decl_all_modules<'a>( runtime: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, ) -> TokenStream2 { let mut types = TokenStream2::new(); let mut names = Vec::new(); @@ -377,7 +457,7 @@ fn decl_all_modules<'a>( } fn decl_module_to_index<'a>( - module_declarations: impl Iterator, + module_declarations: impl Iterator, num_modules: usize, scrate: &TokenStream2, ) -> TokenStream2 { @@ -405,7 +485,7 @@ fn decl_module_to_index<'a>( } fn find_system_module<'a>( - mut module_declarations: impl Iterator, + mut module_declarations: impl Iterator, ) -> Option<&'a Ident> { module_declarations .find(|decl| decl.name == SYSTEM_MODULE_NAME) diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index c8481480baac5..09736f1b9d3d2 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -23,6 +23,7 @@ use syn::{ spanned::Spanned, token, Error, Ident, Result, Token, }; +use core::convert::TryFrom; mod keyword { syn::custom_keyword!(Block); @@ -149,14 +150,22 @@ impl Parse for WhereDefinition { } } -#[derive(Debug)] -pub struct ModuleDeclaration { +#[derive(Debug, Clone)] +pub struct ExpandedModuleDeclaration { pub name: Ident, pub module: Ident, pub instance: Option, pub module_parts: Vec, } +#[derive(Debug, Clone)] +pub struct ModuleDeclaration { + pub name: Ident, + pub module: Ident, + pub instance: Option, + pub module_parts: Option>, +} + impl Parse for ModuleDeclaration { fn parse(input: ParseStream) -> Result { let name = input.parse()?; @@ -172,8 +181,12 @@ impl Parse for ModuleDeclaration { None }; - let _: Token![::] = input.parse()?; - let module_parts = parse_module_parts(input)?; + let module_parts = if input.peek(Token![::]) { + let _: Token![::] = input.parse()?; + Some(parse_module_parts(input)?) + } else { + None + }; let parsed = Self { name, @@ -186,7 +199,23 @@ impl Parse for ModuleDeclaration { } } -impl ModuleDeclaration { +impl TryFrom for ExpandedModuleDeclaration { + type Error = (); + fn try_from(m: ModuleDeclaration) -> core::result::Result { + if m.module_parts.is_some() { + Ok(ExpandedModuleDeclaration { + name: m.name, + module: m.module, + instance: m.instance, + module_parts: m.module_parts.unwrap(), + }) + } else { + Err(()) + } + } +} + +impl ExpandedModuleDeclaration { /// Get resolved module parts pub fn module_parts(&self) -> &[ModulePart] { &self.module_parts diff --git a/frame/support/procedural/src/construct_runtime_args.rs b/frame/support/procedural/src/construct_runtime_args.rs new file mode 100644 index 0000000000000..66c9458b3a27b --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_args.rs @@ -0,0 +1,79 @@ +// This file is part of Substrate. + +// Copyright (C) 2020 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 macro `construct_runtime_args`. + +mod keyword { + syn::custom_keyword!(unique_id); +} + +pub fn decl_construct_runtime_args(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + use frame_support_procedural_tools::generate_crate_access; + + let def = syn::parse_macro_input!(input as DeclArgsDef); + let args = &def.args; + + // frame-support is made available by construct_runtime_preprocess + let hidden_crate_name = "construct_runtime_preprocess"; + let scrate = generate_crate_access(&hidden_crate_name, "frame-support"); + + let hidden_macro_name = syn::Ident::new( + &format!("__hidden_unique_construct_runtime_args_{}", def.unique_id), + proc_macro2::Span::call_site(), + ); + + quote::quote!( + /// This can be internally called by `construct_runtime` to builds the pallet args. + #[macro_export] + #[doc(hidden)] + macro_rules! #hidden_macro_name { + ( { $( $pattern:tt )* } $( $t:tt )* ) => { + #scrate::expand_after! { + { $( $pattern )* } + { ::{ #args } } + $( $t )* + } + } + } + #[doc(inline)] + pub use #hidden_macro_name as construct_runtime_args; + ).into() +} + +struct DeclArgsDef { + unique_id: String, + args: proc_macro2::TokenStream, +} + +impl syn::parse::Parse for DeclArgsDef { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let unique_id = if input.peek(syn::Token![#]) { + input.parse::()?; + let content; + syn::bracketed!(content in input); + content.parse::()?; + content.parse::()?; + format!("{}", content.parse::()?) + } else { + "default_unique_id".into() + }; + + let args = input.parse()?; + + Ok(Self { unique_id, args }) + } +} diff --git a/frame/support/procedural/src/expand_after.rs b/frame/support/procedural/src/expand_after.rs new file mode 100644 index 0000000000000..64c8114782ad8 --- /dev/null +++ b/frame/support/procedural/src/expand_after.rs @@ -0,0 +1,134 @@ +// This file is part of Substrate. + +// Copyright (C) 2020 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 macro `expand_after`. + +use proc_macro2::{TokenStream, TokenTree, Group, Span}; +use syn::spanned::Spanned; +use std::iter::once; + +pub fn expand_after(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let def = syn::parse_macro_input!(input as ExpandAfterDef); + let expand_in_span = def.expand_in.span(); + + match expand_in_stream(&def.expand_after, &mut Some(def.expand_with), def.expand_in) { + Ok(stream) => stream.into(), + Err(_) => { + let msg = format!("Cannot find pattern `{:?}` in given token stream", def.expand_after); + syn::Error::new(expand_in_span, msg).to_compile_error().into() + }, + } +} + +struct ExpandAfterDef { + // Pattern to expand after, this is ensured to have no TokenTree::Group nor TokenTree::Literal + // (i.e. contains only Punct or Ident), and not being empty. + expand_after: Vec, + // Token stream to write after match. + expand_with: TokenStream, + // Token stream to search and write inside. + expand_in: TokenStream, +} + +impl syn::parse::Parse for ExpandAfterDef { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let expand_after; + let _replace_with_bracket: syn::token::Brace = syn::braced!(expand_after in input); + let expand_after = expand_after.parse::()? + .into_iter().collect::>(); + + if let Some(t) = expand_after.iter().find(|t| matches!(t, TokenTree::Group(_))) { + return Err(syn::Error::new(t.span(), "Unexpected group token tree")); + } + if let Some(t) = expand_after.iter().find(|t| matches!(t, TokenTree::Literal(_))) { + return Err(syn::Error::new(t.span(), "Unexpected literal token tree")); + } + + if expand_after.is_empty() { + return Err(syn::Error::new(Span::call_site(), "empty match pattern is invalid")); + } + + let expand_with; + let _replace_with_bracket: syn::token::Brace = syn::braced!(expand_with in input); + let expand_with: TokenStream = expand_with.parse()?; + + Ok(Self { + expand_with, + expand_after, + expand_in: input.parse()?, + }) + } +} + +// Replace the first found `after` pattern by content of `with`. +// `with` must be some (Option is used for internal simplification). +// `after` musn't be empty and only contains Ident or Punct +fn expand_in_stream( + after: &Vec, + with: &mut Option, + stream: TokenStream +) -> Result { + assert!(with.is_some(), "`with` must be some, Option is used because `with` is used only once"); + assert!(!after.is_empty(), "`after` mustn't be empty, otherwise it cannot be found"); + + let mut stream = stream.into_iter(); + let mut extended = TokenStream::new(); + let mut match_cursor = 0; + + loop { + match stream.next() { + Some(TokenTree::Group(group)) => { + match_cursor = 0; + let stream = group.stream(); + match expand_in_stream(after, with, stream) { + Ok(stream) => { + extended.extend(once(TokenTree::Group(Group::new(group.delimiter(), stream)))); + break; + } + Err(_) => { + extended.extend(once(TokenTree::Group(group))); + } + } + } + Some(other) => { + use TokenTree::{Ident, Punct}; + + let other_match_pattern = match (&other, &after[match_cursor]) { + (Ident(i1), Ident(i2)) if i1 == i2 => true, + (Punct(p1), Punct(p2)) if p1.as_char() == p2.as_char() => true, + _ => false, + }; + + if other_match_pattern { + match_cursor += 1 + } + + extended.extend(once(other)); + + if match_cursor == after.len() { + extended.extend(once(with.take().expect("with is used to replace only once"))); + break; + } + } + None => return Err(()) + } + } + + extended.extend(stream); + + Ok(extended) +} diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 57c6080a90f0a..78ecbf8922c43 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -23,6 +23,8 @@ mod storage; mod construct_runtime; +mod expand_after; +mod construct_runtime_args; use proc_macro::TokenStream; @@ -260,6 +262,8 @@ pub fn decl_storage(input: TokenStream) -> TokenStream { /// // Module with instances /// Test3_Instance1: test3::::{Module, Call, Storage, Event, Config, Origin}, /// Test3_DefaultInstance: test3::{Module, Call, Storage, Event, Config, Origin}, +/// +/// TestAuto: pallet_with_automatic_expansion, /// } /// ) /// ``` @@ -280,12 +284,79 @@ pub fn decl_storage(input: TokenStream) -> TokenStream { /// - `Inherent` - If the module provides/can check inherents. /// - `ValidateUnsigned` - If the module validates unsigned extrinsics. /// +/// if no module parts is provided construct_runtime will try to use the expansion provided by the +/// crate through `decl_construct_runtime_args`. +/// /// # Note /// /// The population of the genesis storage depends on the order of modules. So, if one of your /// modules depends on another module, the module that is depended upon needs to come before /// the module depending on it. +/// ``` #[proc_macro] pub fn construct_runtime(input: TokenStream) -> TokenStream { construct_runtime::construct_runtime(input) } + +/// Macro than expand after the first finding of some pattern. +/// +/// # Example: +/// +/// ```nocompile +/// expand_after!( +/// { match pattern } // the match pattern cannot contains any group: `[]`, `()`, `{}`. +/// { expansion tokens } // content inside braces can be anything including groups. +/// Some content with { at some point match pattern } other match pattern are ignored +/// ); +/// ``` +/// +/// will generate: +/// +/// ```nocompile +/// Some content with { at some point match pattern expansion tokens } other match pattern are +/// ignored +/// ``` +#[proc_macro] +pub fn expand_after(input: TokenStream) -> TokenStream { + expand_after::expand_after(input) +} + +/// Declare the construct_runtime_args to be used in construct_runtime to get the default pallet +/// parts. +/// +/// # Example: +/// +/// if pallet want to give the given args: +/// ```nocompile +/// construct_runtime!( +/// ... +/// { +/// ... +/// Example: frame_example::{Module, Call, Event}, +/// ... +/// } +/// ); +/// ``` +/// +/// then it must define: +/// +/// ```nocompile +/// decl_construct_runtime_args!(Module, Call, Event) +/// ``` +/// +/// if multiple pallet are defined in the same crate, then a unique id must be used internally, the +/// unique id is declared as such: +/// +/// ```nocompile +/// decl_construct_runtime_args!(#[unique_id = $id] Module, Call, Event) +/// ``` +/// +/// `$id` is only used internally and just need to be unique for the crate. +// The defined macro construct_runtime_args must be called as such: +// ``` +// construct_runtime_args!( { pattern to find } tokens to find pattern in and expand after ) +// ``` +#[proc_macro] +pub fn decl_construct_runtime_args(input: TokenStream) -> TokenStream { + construct_runtime_args::decl_construct_runtime_args(input) +} diff --git a/frame/support/procedural/src/storage/genesis_config/mod.rs b/frame/support/procedural/src/storage/genesis_config/mod.rs index 7cc0f7c3befd4..732a241297157 100644 --- a/frame/support/procedural/src/storage/genesis_config/mod.rs +++ b/frame/support/procedural/src/storage/genesis_config/mod.rs @@ -65,6 +65,7 @@ fn decl_genesis_config_and_impl_default( let genesis_struct = &genesis_config.genesis_struct; let genesis_impl = &genesis_config.genesis_impl; let genesis_where_clause = &genesis_config.genesis_where_clause; + let serde_crate = syn::LitStr::new(&format!("{}::serde", scrate), Span::call_site()); quote!( /// Genesis config for the module, allow to build genesis storage. @@ -72,6 +73,7 @@ fn decl_genesis_config_and_impl_default( #[cfg(feature = "std")] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] + #[serde(crate = #serde_crate)] #serde_bug_bound pub struct GenesisConfig#genesis_struct_decl #genesis_where_clause { #( #config_fields )* diff --git a/frame/support/src/inherent.rs b/frame/support/src/inherent.rs index e9b0c22692e9d..47672ba6653ba 100644 --- a/frame/support/src/inherent.rs +++ b/frame/support/src/inherent.rs @@ -74,6 +74,7 @@ macro_rules! impl_outer_inherent { fn check_extrinsics(&self, block: &$block) -> $crate::inherent::CheckInherentsResult { use $crate::inherent::{ProvideInherent, IsFatalError}; + use $crate::sp_runtime::traits::Block as _; use $crate::dispatch::IsSubType; let mut result = $crate::inherent::CheckInherentsResult::new(); diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 06a8ce856dd64..5ca59213becf5 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -267,7 +267,9 @@ macro_rules! ord_parameter_types { } #[doc(inline)] -pub use frame_support_procedural::{decl_storage, construct_runtime}; +pub use frame_support_procedural::{ + decl_storage, construct_runtime, expand_after, decl_construct_runtime_args, +}; /// Return Err of the expression: `return Err($expression);`. /// diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 10fc3319fb080..8f6d2e1363a2e 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -21,7 +21,7 @@ #![recursion_limit="128"] -use sp_runtime::{generic, traits::{BlakeTwo256, Block as _, Verify}, DispatchError}; +use sp_runtime::{generic, traits::{BlakeTwo256, Verify}, DispatchError}; use sp_core::{H256, sr25519}; use sp_std::cell::RefCell; diff --git a/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.stderr b/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.stderr index 3b967f96d7b4e..8a6f15f7915b2 100644 --- a/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.stderr +++ b/frame/support/test/tests/construct_runtime_ui/invalid_token_after_module.stderr @@ -1,4 +1,4 @@ -error: expected `::` +error: expected `,` --> $DIR/invalid_token_after_module.rs:9:18 | 9 | system: System ? diff --git a/frame/support/test/tests/construct_runtime_ui/missing_construct_runtime_args.rs b/frame/support/test/tests/construct_runtime_ui/missing_construct_runtime_args.rs new file mode 100644 index 0000000000000..14e1b66daedc7 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/missing_construct_runtime_args.rs @@ -0,0 +1,16 @@ +use frame_support::construct_runtime; + +mod system { +} + +construct_runtime! { + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/missing_construct_runtime_args.stderr b/frame/support/test/tests/construct_runtime_ui/missing_construct_runtime_args.stderr new file mode 100644 index 0000000000000..08e97fd7ed4f5 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/missing_construct_runtime_args.stderr @@ -0,0 +1,5 @@ +error[E0433]: failed to resolve: could not find `construct_runtime_args` in `system` + --> $DIR/missing_construct_runtime_args.rs:12:3 + | +12 | System: system, + | ^^^^^^ could not find `construct_runtime_args` in `system` diff --git a/frame/support/test/tests/expand_after.rs b/frame/support/test/tests/expand_after.rs new file mode 100644 index 0000000000000..2d8d62617de11 --- /dev/null +++ b/frame/support/test/tests/expand_after.rs @@ -0,0 +1,22 @@ +// Assert symbol are correctly matching. +frame_support::expand_after!( + { a + b, } + { a + 2 } + #[test] + fn expand_after_works() { + let a = 5; + let b = 2; + assert_eq!(a + b,); + } +); + +// Assert only first match is expanded after. +frame_support::expand_after!( + { a + } + { 1 + } + #[test] + fn expand_after_unique_expand_works() { + let a = 1; + assert_eq!(a + a, 3 * a); + } +); diff --git a/frame/support/test/tests/instance.rs b/frame/support/test/tests/instance.rs index 08389eed3aa83..89cb1b0b994d2 100644 --- a/frame/support/test/tests/instance.rs +++ b/frame/support/test/tests/instance.rs @@ -18,9 +18,9 @@ #![recursion_limit="128"] use codec::{Codec, EncodeLike, Encode, Decode}; -use sp_runtime::{generic, BuildStorage, traits::{BlakeTwo256, Block as _, Verify}}; +use sp_runtime::{generic, BuildStorage, traits::{BlakeTwo256, Verify}}; use frame_support::{ - Parameter, traits::Get, parameter_types, + Parameter, traits::Get, parameter_types, decl_construct_runtime_args, metadata::{ DecodeDifferent, StorageMetadata, StorageEntryModifier, StorageEntryType, DefaultByteGetter, StorageEntryMetadata, StorageHasher, @@ -41,6 +41,10 @@ pub trait Currency {} mod module1 { use super::*; + decl_construct_runtime_args!(#[unique_id = _1] + Module, Call, Storage, Config, Event, Origin, Inherent + ); + pub trait Trait: system::Trait where ::BlockNumber: From { type Event: From> + Into<::Event>; type Origin: From>; @@ -120,6 +124,8 @@ mod module1 { mod module2 { use super::*; + decl_construct_runtime_args!(Module, Call, Storage, Config, Event, Origin, Inherent); + pub trait Trait: system::Trait { type Amount: Parameter + Default; type Event: From> + Into<::Event>; @@ -179,6 +185,8 @@ mod module2 { mod module3 { use super::*; + decl_construct_runtime_args!(#[unique_id = _3] Module, Call); + pub trait Trait: module2::Trait + module2::Trait + system::Trait { type Currency: Currency; type Currency2: Currency; @@ -253,29 +261,19 @@ frame_support::construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic { System: system::{Module, Call, Event}, - Module1_1: module1::::{ - Module, Call, Storage, Event, Config, Origin, Inherent - }, - Module1_2: module1::::{ - Module, Call, Storage, Event, Config, Origin, Inherent - }, - Module2: module2::{Module, Call, Storage, Event, Config, Origin, Inherent}, - Module2_1: module2::::{ - Module, Call, Storage, Event, Config, Origin, Inherent - }, - Module2_2: module2::::{ - Module, Call, Storage, Event, Config, Origin, Inherent - }, - Module2_3: module2::::{ - Module, Call, Storage, Event, Config, Origin, Inherent - }, - Module3: module3::{Module, Call}, + Module1_1: module1::, + Module1_2: module1::, + Module2: module2, + Module2_1: module2::, + Module2_2: module2::, + Module2_3: module2::, + Module3: module3, } ); pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<(), Call, (), ()>; fn new_test_ext() -> sp_io::TestExternalities { GenesisConfig{ diff --git a/frame/support/test/tests/issue2219.rs b/frame/support/test/tests/issue2219.rs index 7166f202c7325..0b057e930de25 100644 --- a/frame/support/test/tests/issue2219.rs +++ b/frame/support/test/tests/issue2219.rs @@ -16,7 +16,7 @@ // limitations under the License. use frame_support::sp_runtime::generic; -use frame_support::sp_runtime::traits::{BlakeTwo256, Block as _, Verify}; +use frame_support::sp_runtime::traits::{BlakeTwo256, Verify}; use frame_support::codec::{Encode, Decode}; use sp_core::{H256, sr25519}; use serde::{Serialize, Deserialize}; diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index ad68e97d462ad..e5a9921f721da 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -107,15 +107,15 @@ use sp_runtime::{ self, CheckEqual, AtLeast32Bit, Zero, Lookup, LookupError, SimpleBitOps, Hash, Member, MaybeDisplay, BadOrigin, MaybeSerialize, MaybeSerializeDeserialize, MaybeMallocSizeOf, StaticLookup, One, Bounded, - Dispatchable, AtLeast32BitUnsigned + Dispatchable, AtLeast32BitUnsigned, BlakeTwo256, }, offchain::storage_lock::BlockNumberProvider, }; use sp_core::{ChangesTrieConfiguration, storage::well_known_keys}; use frame_support::{ - decl_module, decl_event, decl_storage, decl_error, Parameter, ensure, debug, - storage, + decl_module, decl_event, decl_storage, decl_error, Parameter, ensure, debug, storage, + decl_construct_runtime_args, traits::{ Contains, Get, ModuleToIndex, OnNewAccount, OnKilledAccount, IsDeadAccount, Happened, StoredMap, EnsureOrigin, OriginTrait, Filter, @@ -148,6 +148,8 @@ pub use extensions::{ // Backward compatible re-export. pub use extensions::check_mortality::CheckMortality as CheckEra; +decl_construct_runtime_args!(Module, Call, Config, Storage, Event); + /// Compute the trie root of a list of extrinsics. pub fn extrinsics_root(extrinsics: &[E]) -> H::Output { extrinsics_data_root::(extrinsics.iter().map(codec::Encode::encode).collect()) @@ -1375,3 +1377,14 @@ impl Lookup for ChainContext { ::lookup(s) } } + +/// An implementation of `sp_runtime::traits::Block` to be used in test. +pub type MockBlock = generic::Block< + generic::Header<::BlockNumber, BlakeTwo256>, + MockUncheckedExtrinsic, +>; + +/// An unchecked extrinsic type to be used in test. +pub type MockUncheckedExtrinsic = generic::UncheckedExtrinsic< + ::AccountId, ::Call, (), (), +>; diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 02031a2df9a55..d521d3dd34b91 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -609,9 +609,18 @@ macro_rules! __impl_outer_config_types { /// rust_module_one: Option, /// ... /// } +/// +/// Optionally serde crate can be given, it must be same version as serde used in sp_runtime, +/// syntax is: +/// ```nocompile +/// impl_outer_config { serde_crate { "my_serde_crate" } +/// ... +/// } +/// ``` #[macro_export] macro_rules! impl_outer_config { ( + $( serde_crate { $serde_crate:expr } )? pub struct $main:ident for $concrete:ident { $( $config:ident => $snake:ident $( $instance:ident )? $( <$generic:ident> )*, )* @@ -624,6 +633,7 @@ macro_rules! impl_outer_config { $crate::paste::item! { #[cfg(any(feature = "std", test))] #[derive($crate::serde::Serialize, $crate::serde::Deserialize)] + $( #[serde(crate = $serde_crate )] )? #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct $main {