Adds instance support for composite enums (#1857)

Fixes https://github.com/paritytech/polkadot-sdk/issues/1839

Currently, `composite_enum`s do not support pallet instances. This PR
allows the following:
```rust
	#[pallet::composite_enum]
	pub enum HoldReason<I: 'static = ()> {
		SomeHoldReason
	}
```

### Todo

- [x]  UI Test
This commit is contained in:
gupnik
2023-10-13 07:48:51 +02:00
committed by GitHub
parent d2fc1d7c91
commit 6b27dad359
11 changed files with 264 additions and 93 deletions
@@ -0,0 +1,70 @@
// 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
use crate::construct_runtime::parse::PalletPath;
use proc_macro2::{Ident, TokenStream};
use quote::quote;
pub(crate) fn expand_conversion_fn(
composite_name: &str,
path: &PalletPath,
instance: Option<&Ident>,
variant_name: &Ident,
) -> TokenStream {
let composite_name = quote::format_ident!("{}", composite_name);
let runtime_composite_name = quote::format_ident!("Runtime{}", composite_name);
if let Some(inst) = instance {
quote! {
impl From<#path::#composite_name<#path::#inst>> for #runtime_composite_name {
fn from(hr: #path::#composite_name<#path::#inst>) -> Self {
#runtime_composite_name::#variant_name(hr)
}
}
}
} else {
quote! {
impl From<#path::#composite_name> for #runtime_composite_name {
fn from(hr: #path::#composite_name) -> Self {
#runtime_composite_name::#variant_name(hr)
}
}
}
}
}
pub(crate) fn expand_variant(
composite_name: &str,
index: u8,
path: &PalletPath,
instance: Option<&Ident>,
variant_name: &Ident,
) -> TokenStream {
let composite_name = quote::format_ident!("{}", composite_name);
if let Some(inst) = instance {
quote! {
#[codec(index = #index)]
#variant_name(#path::#composite_name<#path::#inst>),
}
} else {
quote! {
#[codec(index = #index)]
#variant_name(#path::#composite_name),
}
}
}
@@ -15,8 +15,9 @@
// See the License for the specific language governing permissions and
// limitations under the License
use crate::construct_runtime::{parse::PalletPath, Pallet};
use proc_macro2::{Ident, TokenStream};
use super::composite_helper;
use crate::construct_runtime::Pallet;
use proc_macro2::TokenStream;
use quote::quote;
pub fn expand_outer_freeze_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream {
@@ -27,17 +28,29 @@ pub fn expand_outer_freeze_reason(pallet_decls: &[Pallet], scrate: &TokenStream)
let variant_name = &decl.name;
let path = &decl.path;
let index = decl.index;
let instance = decl.instance.as_ref();
conversion_fns.push(expand_conversion_fn(path, variant_name));
conversion_fns.push(composite_helper::expand_conversion_fn(
"FreezeReason",
path,
instance,
variant_name,
));
freeze_reason_variants.push(expand_variant(index, path, variant_name));
freeze_reason_variants.push(composite_helper::expand_variant(
"FreezeReason",
index,
path,
instance,
variant_name,
));
}
}
quote! {
/// A reason for placing a freeze on funds.
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
Copy, Clone, Eq, PartialEq,
#scrate::__private::codec::Encode, #scrate::__private::codec::Decode, #scrate::__private::codec::MaxEncodedLen,
#scrate::__private::scale_info::TypeInfo,
#scrate::__private::RuntimeDebug,
@@ -49,20 +62,3 @@ pub fn expand_outer_freeze_reason(pallet_decls: &[Pallet], scrate: &TokenStream)
#( #conversion_fns )*
}
}
fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream {
quote! {
impl From<#path::FreezeReason> for RuntimeFreezeReason {
fn from(hr: #path::FreezeReason) -> Self {
RuntimeFreezeReason::#variant_name(hr)
}
}
}
}
fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream {
quote! {
#[codec(index = #index)]
#variant_name(#path::FreezeReason),
}
}
@@ -15,8 +15,9 @@
// See the License for the specific language governing permissions and
// limitations under the License
use crate::construct_runtime::{parse::PalletPath, Pallet};
use proc_macro2::{Ident, TokenStream};
use super::composite_helper;
use crate::construct_runtime::Pallet;
use proc_macro2::TokenStream;
use quote::quote;
pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream {
@@ -27,17 +28,29 @@ pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -
let variant_name = &decl.name;
let path = &decl.path;
let index = decl.index;
let instance = decl.instance.as_ref();
conversion_fns.push(expand_conversion_fn(path, variant_name));
conversion_fns.push(composite_helper::expand_conversion_fn(
"HoldReason",
path,
instance,
variant_name,
));
hold_reason_variants.push(expand_variant(index, path, variant_name));
hold_reason_variants.push(composite_helper::expand_variant(
"HoldReason",
index,
path,
instance,
variant_name,
));
}
}
quote! {
/// A reason for placing a hold on funds.
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
Copy, Clone, Eq, PartialEq,
#scrate::__private::codec::Encode, #scrate::__private::codec::Decode, #scrate::__private::codec::MaxEncodedLen,
#scrate::__private::scale_info::TypeInfo,
#scrate::__private::RuntimeDebug,
@@ -49,20 +62,3 @@ pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -
#( #conversion_fns )*
}
}
fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream {
quote! {
impl From<#path::HoldReason> for RuntimeHoldReason {
fn from(hr: #path::HoldReason) -> Self {
RuntimeHoldReason::#variant_name(hr)
}
}
}
}
fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream {
quote! {
#[codec(index = #index)]
#variant_name(#path::HoldReason),
}
}
@@ -15,8 +15,9 @@
// See the License for the specific language governing permissions and
// limitations under the License
use crate::construct_runtime::{parse::PalletPath, Pallet};
use proc_macro2::{Ident, TokenStream};
use super::composite_helper;
use crate::construct_runtime::Pallet;
use proc_macro2::TokenStream;
use quote::quote;
pub fn expand_outer_lock_id(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream {
@@ -27,17 +28,29 @@ pub fn expand_outer_lock_id(pallet_decls: &[Pallet], scrate: &TokenStream) -> To
let variant_name = &decl.name;
let path = &decl.path;
let index = decl.index;
let instance = decl.instance.as_ref();
conversion_fns.push(expand_conversion_fn(path, variant_name));
conversion_fns.push(composite_helper::expand_conversion_fn(
"LockId",
path,
instance,
variant_name,
));
lock_id_variants.push(expand_variant(index, path, variant_name));
lock_id_variants.push(composite_helper::expand_variant(
"LockId",
index,
path,
instance,
variant_name,
));
}
}
quote! {
/// An identifier for each lock placed on funds.
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
Copy, Clone, Eq, PartialEq,
#scrate::__private::codec::Encode, #scrate::__private::codec::Decode, #scrate::__private::codec::MaxEncodedLen,
#scrate::__private::scale_info::TypeInfo,
#scrate::__private::RuntimeDebug,
@@ -49,20 +62,3 @@ pub fn expand_outer_lock_id(pallet_decls: &[Pallet], scrate: &TokenStream) -> To
#( #conversion_fns )*
}
}
fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream {
quote! {
impl From<#path::LockId> for RuntimeLockId {
fn from(hr: #path::LockId) -> Self {
RuntimeLockId::#variant_name(hr)
}
}
}
}
fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream {
quote! {
#[codec(index = #index)]
#variant_name(#path::LockId),
}
}
@@ -16,6 +16,7 @@
// limitations under the License
mod call;
pub mod composite_helper;
mod config;
mod freeze_reason;
mod hold_reason;
@@ -15,8 +15,9 @@
// See the License for the specific language governing permissions and
// limitations under the License
use crate::construct_runtime::{parse::PalletPath, Pallet};
use proc_macro2::{Ident, TokenStream};
use super::composite_helper;
use crate::construct_runtime::Pallet;
use proc_macro2::TokenStream;
use quote::quote;
pub fn expand_outer_slash_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream {
@@ -27,17 +28,29 @@ pub fn expand_outer_slash_reason(pallet_decls: &[Pallet], scrate: &TokenStream)
let variant_name = &decl.name;
let path = &decl.path;
let index = decl.index;
let instance = decl.instance.as_ref();
conversion_fns.push(expand_conversion_fn(path, variant_name));
conversion_fns.push(composite_helper::expand_conversion_fn(
"SlashReason",
path,
instance,
variant_name,
));
slash_reason_variants.push(expand_variant(index, path, variant_name));
slash_reason_variants.push(composite_helper::expand_variant(
"SlashReason",
index,
path,
instance,
variant_name,
));
}
}
quote! {
/// A reason for slashing funds.
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
Copy, Clone, Eq, PartialEq,
#scrate::__private::codec::Encode, #scrate::__private::codec::Decode, #scrate::__private::codec::MaxEncodedLen,
#scrate::__private::scale_info::TypeInfo,
#scrate::__private::RuntimeDebug,
@@ -49,20 +62,3 @@ pub fn expand_outer_slash_reason(pallet_decls: &[Pallet], scrate: &TokenStream)
#( #conversion_fns )*
}
}
fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream {
quote! {
impl From<#path::SlashReason> for RuntimeSlashReason {
fn from(hr: #path::SlashReason) -> Self {
RuntimeSlashReason::#variant_name(hr)
}
}
}
}
fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream {
quote! {
#[codec(index = #index)]
#variant_name(#path::SlashReason),
}
}
@@ -15,6 +15,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use super::helper;
use quote::ToTokens;
use syn::spanned::Spanned;
@@ -108,6 +109,13 @@ impl CompositeDef {
return Err(syn::Error::new(item.span(), msg))
}
let has_instance = if item.generics.params.first().is_some() {
helper::check_config_def_gen(&item.generics, item.ident.span())?;
true
} else {
false
};
let has_derive_attr = item.attrs.iter().any(|attr| {
if let syn::Meta::List(syn::MetaList { path, .. }) = &attr.meta {
path.get_ident().map(|ident| ident == "derive").unwrap_or(false)
@@ -119,7 +127,7 @@ impl CompositeDef {
if !has_derive_attr {
let derive_attr: syn::Attribute = syn::parse_quote! {
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
Copy, Clone, Eq, PartialEq,
#scrate::__private::codec::Encode, #scrate::__private::codec::Decode, #scrate::__private::codec::MaxEncodedLen,
#scrate::__private::scale_info::TypeInfo,
#scrate::__private::RuntimeDebug,
@@ -128,6 +136,20 @@ impl CompositeDef {
item.attrs.push(derive_attr);
}
if has_instance {
item.attrs.push(syn::parse_quote! {
#[scale_info(skip_type_params(I))]
});
item.variants.push(syn::parse_quote! {
#[doc(hidden)]
#[codec(skip)]
__Ignore(
#scrate::__private::sp_std::marker::PhantomData<I>,
)
});
}
let composite_keyword =
syn::parse2::<keyword::CompositeKeyword>(item.ident.to_token_stream())?;