Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

construct_runtime auto pallet parts: allow pallets to expand { Event, Call... } automatically. #6494

Closed
wants to merge 11 commits into from
2 changes: 1 addition & 1 deletion frame/collective/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion frame/elections-phragmen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion frame/elections/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion frame/offences/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};

Expand Down
108 changes: 94 additions & 14 deletions frame/support/procedural/src/construct_runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Option<TokenStream2>> {
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<TokenStream2> {
let RuntimeDefinition {
name,
Expand All @@ -52,6 +109,15 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream
..
} = definition;

// All modules have been expanded, thus we convert to the expanded definition.
let modules: Vec<ExpandedModuleDeclaration> = modules.into_iter()
.map(TryFrom::try_from)
.collect::<core::result::Result<_, _>>()
.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,
Expand All @@ -77,7 +143,7 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream

let outer_origin = decl_outer_origin(
&name,
all_but_system_modules.clone(),
all_but_system_modules,
&system_module,
&scrate,
)?;
Expand Down Expand Up @@ -134,7 +200,7 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream

fn decl_validate_unsigned<'a>(
runtime: &'a Ident,
module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
module_declarations: impl Iterator<Item = &'a ExpandedModuleDeclaration>,
scrate: &'a TokenStream2,
) -> TokenStream2 {
let modules_tokens = module_declarations
Expand All @@ -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<Item = &'a ModuleDeclaration>,
module_declarations: impl Iterator<Item = &'a ExpandedModuleDeclaration>,
scrate: &'a TokenStream2,
) -> TokenStream2 {
let modules_tokens = module_declarations.filter_map(|module_declaration| {
Expand All @@ -163,6 +229,12 @@ fn decl_outer_inherent<'a>(
})
});
quote!(
// Prevent UncheckedExtrinsic to print unused warning.
const _: () = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this pattern in the expansions of derive macros of codec as well, what is the purpose? is the keyword __hidden_use_unchecked_extrinsic used anywhere now?

Copy link
Contributor Author

@gui1117 gui1117 Aug 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, keyword __hidden_use_unchecked_extrinsic is not used anywhere, warpping in const is a pattern used by many derive macro, for instance serde.
I think the main advantage is that it makes type __hidden_use_unchecked_extrinsic unavailable in doc and rust error will not recommand it.

Copy link
Contributor

@kianenigma kianenigma Aug 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if the type alias is not even accessible and used anywhere, I don't see how it is used.

For example I've this and it makes sense:

const _: () { impl Something for SomethingElse { ... } } 

but something like:

const _: () = { type __unused_alias = Foo; }

I don't get.

Unless is __hidden_use_unchecked_extrinsic used in the other branch? Asking because I couldn't find any usage here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just to // Prevent UncheckedExtrinsic to print unused warning.
so I have const _: () = { #[allow(unused)] type __unused_alias = Foo; }
UncheckedExtrinsic is unused if there is no inherent.

#[allow(unused)]
type __hidden_use_unchecked_extrinsic = #unchecked_extrinsic;
};

#scrate::impl_outer_inherent!(
impl Inherents where
Block = #block,
Expand All @@ -176,7 +248,7 @@ fn decl_outer_inherent<'a>(

fn decl_outer_config<'a>(
runtime: &'a Ident,
module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
module_declarations: impl Iterator<Item = &'a ExpandedModuleDeclaration>,
scrate: &'a TokenStream2,
) -> TokenStream2 {
let modules_tokens = module_declarations
Expand All @@ -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)*
}
Expand All @@ -214,7 +294,7 @@ fn decl_outer_config<'a>(

fn decl_runtime_metadata<'a>(
runtime: &'a Ident,
module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
module_declarations: impl Iterator<Item = &'a ExpandedModuleDeclaration>,
scrate: &'a TokenStream2,
extrinsic: &TypePath,
) -> TokenStream2 {
Expand Down Expand Up @@ -250,7 +330,7 @@ fn decl_runtime_metadata<'a>(

fn decl_outer_dispatch<'a>(
runtime: &'a Ident,
module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
module_declarations: impl Iterator<Item = &'a ExpandedModuleDeclaration>,
scrate: &'a TokenStream2,
) -> TokenStream2 {
let modules_tokens = module_declarations
Expand All @@ -271,7 +351,7 @@ fn decl_outer_dispatch<'a>(

fn decl_outer_origin<'a>(
runtime_name: &'a Ident,
module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
module_declarations: impl Iterator<Item = &'a ExpandedModuleDeclaration>,
system_name: &'a Ident,
scrate: &'a TokenStream2,
) -> syn::Result<TokenStream2> {
Expand Down Expand Up @@ -308,7 +388,7 @@ fn decl_outer_origin<'a>(

fn decl_outer_event<'a>(
runtime_name: &'a Ident,
module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
module_declarations: impl Iterator<Item = &'a ExpandedModuleDeclaration>,
scrate: &'a TokenStream2,
) -> syn::Result<TokenStream2> {
let mut modules_tokens = TokenStream2::new();
Expand Down Expand Up @@ -344,7 +424,7 @@ fn decl_outer_event<'a>(

fn decl_all_modules<'a>(
runtime: &'a Ident,
module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
module_declarations: impl Iterator<Item = &'a ExpandedModuleDeclaration>,
) -> TokenStream2 {
let mut types = TokenStream2::new();
let mut names = Vec::new();
Expand Down Expand Up @@ -377,7 +457,7 @@ fn decl_all_modules<'a>(
}

fn decl_module_to_index<'a>(
module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
module_declarations: impl Iterator<Item = &'a ExpandedModuleDeclaration>,
num_modules: usize,
scrate: &TokenStream2,
) -> TokenStream2 {
Expand Down Expand Up @@ -405,7 +485,7 @@ fn decl_module_to_index<'a>(
}

fn find_system_module<'a>(
mut module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
mut module_declarations: impl Iterator<Item = &'a ExpandedModuleDeclaration>,
) -> Option<&'a Ident> {
module_declarations
.find(|decl| decl.name == SYSTEM_MODULE_NAME)
Expand Down
39 changes: 34 additions & 5 deletions frame/support/procedural/src/construct_runtime/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use syn::{
spanned::Spanned,
token, Error, Ident, Result, Token,
};
use core::convert::TryFrom;

mod keyword {
syn::custom_keyword!(Block);
Expand Down Expand Up @@ -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<Ident>,
pub module_parts: Vec<ModulePart>,
}

#[derive(Debug, Clone)]
pub struct ModuleDeclaration {
pub name: Ident,
pub module: Ident,
pub instance: Option<Ident>,
pub module_parts: Option<Vec<ModulePart>>,
}

impl Parse for ModuleDeclaration {
fn parse(input: ParseStream) -> Result<Self> {
let name = input.parse()?;
Expand All @@ -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,
Expand All @@ -186,7 +199,23 @@ impl Parse for ModuleDeclaration {
}
}

impl ModuleDeclaration {
impl TryFrom<ModuleDeclaration> for ExpandedModuleDeclaration {
type Error = ();
fn try_from(m: ModuleDeclaration) -> core::result::Result<Self, Self::Error> {
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
Expand Down
Loading