Adds ability to provide defaults for types provided by construct_runtime (#14682)

* Adds ability to use defaults for verbatim types

* Adds RuntimeOrigin and PalletInfo in DefaultConfig

* Adds RuntimeEvent in DefaultConfig

* Adds RuntimeEvent in DefaultConfig

* Minor fix

* Minor fix

* Everything in frame_system can now have a default

* Adds docs

* Adds UI Test for no_bounds

* Updates docs

* Adds UI tests for verbatim

* Minor update

* Minor updates

* Minor updates

* Addresses review comments

* Fixes test

* Update frame/support/procedural/src/derive_impl.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* Minor fix

* Minor

* Fixes build

* Uses runtime_type

* Fixes comment

* Fixes comment

* Fixes test

* Uses no_aggregated_types as an option in derive_impl

* Uses specific imports

* Fmt

* Updates doc

* Update frame/support/procedural/src/derive_impl.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update frame/support/procedural/src/derive_impl.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Addresses review comment

* Addresses review comment

* fmt

* Renames test files

* Adds docs using docify

* Fixes test

* Fixes UI tests

---------

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
gupnik
2023-08-25 13:22:22 +05:30
committed by GitHub
parent 32541bde15
commit 83ae018087
21 changed files with 409 additions and 41 deletions
+1
View File
@@ -3002,6 +3002,7 @@ dependencies = [
"sp-std",
"sp-tracing",
"sp-weights",
"static_assertions",
"tt-call",
]
+5 -1
View File
@@ -220,11 +220,14 @@ pub mod pallet {
pub struct TestDefaultConfig;
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)]
impl frame_system::DefaultConfig for TestDefaultConfig {}
#[frame_support::register_default_impl(TestDefaultConfig)]
impl DefaultConfig for TestDefaultConfig {
#[inject_runtime_type]
type RuntimeEvent = ();
type Balance = u64;
type ReserveIdentifier = ();
@@ -242,6 +245,7 @@ pub mod pallet {
#[pallet::config(with_default)]
pub trait Config<I: 'static = ()>: frame_system::Config {
/// The overarching event type.
#[pallet::no_default_bounds]
type RuntimeEvent: From<Event<Self, I>>
+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
@@ -87,7 +87,7 @@ pub mod pallet {
/// A type providing default configurations for this pallet in testing environment.
pub struct TestDefaultConfig;
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)]
impl frame_system::DefaultConfig for TestDefaultConfig {}
#[frame_support::register_default_impl(TestDefaultConfig)]
@@ -109,7 +109,7 @@ pub mod pallet {
/// example, we simple derive `frame_system::config_preludes::TestDefaultConfig` again.
pub struct OtherDefaultConfig;
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)]
impl frame_system::DefaultConfig for OtherDefaultConfig {}
#[frame_support::register_default_impl(OtherDefaultConfig)]
@@ -147,16 +147,7 @@ pub mod tests {
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
impl frame_system::Config for Runtime {
// 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 Block = Block;
type BlockHashCount = frame_support::traits::ConstU64<10>;
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`.
@@ -177,6 +168,17 @@ pub mod tests {
// type BlockWeights = ();
// type BlockLength = ();
// type DbWeight = ();
// type BaseCallFilter = frame_support::traits::Everything;
// type BlockHashCount = frame_support::traits::ConstU64<10>;
// type OnSetCode = ();
// These are marked as `#[inject_runtime_type]`. Hence, they are being injected as
// types generated by `construct_runtime`.
// type RuntimeOrigin = RuntimeOrigin;
// type RuntimeCall = RuntimeCall;
// type RuntimeEvent = RuntimeEvent;
// type PalletInfo = PalletInfo;
// you could still overwrite any of them if desired.
type SS58Prefix = frame_support::traits::ConstU16<456>;
+1
View File
@@ -44,6 +44,7 @@ environmental = { version = "1.1.4", default-features = false }
sp-genesis-builder = { version = "0.1.0", default-features=false, path = "../../primitives/genesis-builder" }
serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] }
docify = "0.2.1"
static_assertions = "1.1.0"
aquamarine = { version = "0.3.2" }
@@ -22,14 +22,46 @@ 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, Ident, ImplItem, ItemImpl, Path, Result, Token};
use syn::{
parse2, parse_quote, spanned::Spanned, token, Ident, ImplItem, ItemImpl, Path, Result, Token,
};
#[derive(Parse)]
mod keyword {
syn::custom_keyword!(inject_runtime_type);
syn::custom_keyword!(no_aggregated_types);
}
#[derive(derive_syn_parse::Parse, PartialEq, Eq)]
pub enum PalletAttrType {
#[peek(keyword::inject_runtime_type, name = "inject_runtime_type")]
RuntimeType(keyword::inject_runtime_type),
}
#[derive(derive_syn_parse::Parse)]
pub struct PalletAttr {
_pound: Token![#],
#[bracket]
_bracket: token::Bracket,
#[inside(_bracket)]
typ: PalletAttrType,
}
fn get_first_item_pallet_attr<Attr>(item: &syn::ImplItemType) -> syn::Result<Option<Attr>>
where
Attr: syn::parse::Parse,
{
item.attrs.get(0).map(|a| syn::parse2(a.into_token_stream())).transpose()
}
#[derive(Parse, Debug)]
pub struct DeriveImplAttrArgs {
pub default_impl_path: Path,
_as: Option<Token![as]>,
#[parse_if(_as.is_some())]
pub disambiguation_path: Option<Path>,
_comma: Option<Token![,]>,
#[parse_if(_comma.is_some())]
pub no_aggregated_types: Option<keyword::no_aggregated_types>,
}
impl ForeignPath for DeriveImplAttrArgs {
@@ -43,6 +75,8 @@ impl ToTokens for DeriveImplAttrArgs {
tokens.extend(self.default_impl_path.to_token_stream());
tokens.extend(self._as.to_token_stream());
tokens.extend(self.disambiguation_path.to_token_stream());
tokens.extend(self._comma.to_token_stream());
tokens.extend(self.no_aggregated_types.to_token_stream());
}
}
@@ -78,6 +112,7 @@ fn combine_impls(
foreign_impl: ItemImpl,
default_impl_path: Path,
disambiguation_path: Path,
inject_runtime_types: bool,
) -> ItemImpl {
let (existing_local_keys, existing_unsupported_items): (HashSet<ImplItem>, HashSet<ImplItem>) =
local_impl
@@ -96,7 +131,20 @@ fn combine_impls(
// do not copy colliding items that have an ident
return None
}
if matches!(item, ImplItem::Type(_)) {
if let ImplItem::Type(typ) = item.clone() {
let mut typ = typ.clone();
if let Ok(Some(PalletAttr { typ: PalletAttrType::RuntimeType(_), .. })) =
get_first_item_pallet_attr::<PalletAttr>(&mut typ)
{
let item: ImplItem = if inject_runtime_types {
parse_quote! {
type #ident = #ident;
}
} else {
item
};
return Some(item)
}
// modify and insert uncolliding type items
let modified_item: ImplItem = parse_quote! {
type #ident = <#default_impl_path as #disambiguation_path>::#ident;
@@ -132,6 +180,7 @@ pub fn derive_impl(
foreign_tokens: TokenStream2,
local_tokens: TokenStream2,
disambiguation_path: Option<Path>,
no_aggregated_types: Option<keyword::no_aggregated_types>,
) -> Result<TokenStream2> {
let local_impl = parse2::<ItemImpl>(local_tokens)?;
let foreign_impl = parse2::<ItemImpl>(foreign_tokens)?;
@@ -151,8 +200,13 @@ pub fn derive_impl(
};
// generate the combined impl
let combined_impl =
combine_impls(local_impl, foreign_impl, default_impl_path, disambiguation_path);
let combined_impl = combine_impls(
local_impl,
foreign_impl,
default_impl_path,
disambiguation_path,
no_aggregated_types.is_none(),
);
Ok(quote!(#combined_impl))
}
+47 -1
View File
@@ -38,7 +38,7 @@ use macro_magic::import_tokens_attr;
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use std::{cell::RefCell, str::FromStr};
use syn::{parse_macro_input, Error, ItemImpl, ItemMod};
use syn::{parse_macro_input, Error, ItemImpl, ItemMod, TraitItemType};
pub(crate) const INHERENT_INSTANCE_NAME: &str = "__InherentHiddenInstance";
@@ -596,6 +596,19 @@ pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> TokenStream
///
/// Conversely, the `default_impl_path` argument is required and cannot be omitted.
///
/// Optionally, `no_aggregated_types` can be specified as follows:
///
/// ```ignore
/// #[derive_impl(default_impl_path as disambiguation_path, no_aggregated_types)]
/// impl SomeTrait for SomeStruct {
/// ...
/// }
/// ```
///
/// If specified, this indicates that the aggregated types (as denoted by impl items
/// attached with [`#[inject_runtime_type]`]) should not be injected with the respective concrete
/// types. By default, all such types are injected.
///
/// 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.
@@ -759,6 +772,7 @@ pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream {
attrs.into(),
input.into(),
custom_attrs.disambiguation_path,
custom_attrs.no_aggregated_types,
)
.unwrap_or_else(|r| r.into_compile_error())
.into()
@@ -774,6 +788,19 @@ pub fn no_default(_: TokenStream, _: TokenStream) -> TokenStream {
pallet_macro_stub()
}
/// The optional attribute `#[pallet::no_default_bounds]` can be attached to trait items within a
/// `Config` trait impl that has [`#[pallet::config(with_default)]`](`macro@config`) attached.
///
/// Attaching this attribute to a trait item ensures that the generated trait `DefaultConfig`
/// will not have any bounds for this trait item.
///
/// As an example, if you have a trait item `type AccountId: SomeTrait;` in your `Config` trait,
/// the generated `DefaultConfig` will only have `type AccountId;` with no trait bound.
#[proc_macro_attribute]
pub fn no_default_bounds(_: TokenStream, _: TokenStream) -> TokenStream {
pallet_macro_stub()
}
/// Attach this attribute to an impl statement that you want to use with
/// [`#[derive_impl(..)]`](`macro@derive_impl`).
///
@@ -843,6 +870,25 @@ pub fn register_default_impl(attrs: TokenStream, tokens: TokenStream) -> TokenSt
}
}
#[proc_macro_attribute]
pub fn inject_runtime_type(_: TokenStream, tokens: TokenStream) -> TokenStream {
let item = tokens.clone();
let item = syn::parse_macro_input!(item as TraitItemType);
if item.ident != "RuntimeCall" &&
item.ident != "RuntimeEvent" &&
item.ident != "RuntimeOrigin" &&
item.ident != "PalletInfo"
{
return syn::Error::new_spanned(
item,
"`#[inject_runtime_type]` can only be attached to `RuntimeCall`, `RuntimeEvent`, `RuntimeOrigin` or `PalletInfo`",
)
.to_compile_error()
.into();
}
tokens
}
/// Used internally to decorate pallet attribute macro stubs when they are erroneously used
/// outside of a pallet module
fn pallet_macro_stub() -> TokenStream {
@@ -52,7 +52,23 @@ Consequently, a runtime that wants to include this pallet must implement this tr
// impossible consequently.
match &config.default_sub_trait {
Some(default_sub_trait) if default_sub_trait.items.len() > 0 => {
let trait_items = &default_sub_trait.items;
let trait_items = &default_sub_trait
.items
.iter()
.map(|item| {
if item.1 {
if let syn::TraitItem::Type(item) = item.0.clone() {
let mut item = item.clone();
item.bounds.clear();
syn::TraitItem::Type(item)
} else {
item.0.clone()
}
} else {
item.0.clone()
}
})
.collect::<Vec<_>>();
let type_param_bounds = if default_sub_trait.has_system {
let system = &def.frame_system;
@@ -34,12 +34,16 @@ mod keyword {
syn::custom_keyword!(frame_system);
syn::custom_keyword!(disable_frame_system_supertrait_check);
syn::custom_keyword!(no_default);
syn::custom_keyword!(no_default_bounds);
syn::custom_keyword!(constant);
}
#[derive(Default)]
pub struct DefaultTrait {
pub items: Vec<syn::TraitItem>,
/// A bool for each sub-trait item indicates whether the item has
/// `#[pallet::no_default_bounds]` attached to it. If true, the item will not have any bounds
/// in the generated default sub-trait.
pub items: Vec<(syn::TraitItem, bool)>,
pub has_system: bool,
}
@@ -142,6 +146,8 @@ impl syn::parse::Parse for DisableFrameSystemSupertraitCheck {
pub enum PalletAttrType {
#[peek(keyword::no_default, name = "no_default")]
NoDefault(keyword::no_default),
#[peek(keyword::no_default_bounds, name = "no_default_bounds")]
NoBounds(keyword::no_default_bounds),
#[peek(keyword::constant, name = "constant")]
Constant(keyword::constant),
}
@@ -366,6 +372,7 @@ impl ConfigDef {
let mut already_no_default = false;
let mut already_constant = false;
let mut already_no_default_bounds = false;
while let Ok(Some(pallet_attr)) =
helper::take_first_item_pallet_attr::<PalletAttr>(trait_item)
@@ -403,15 +410,31 @@ impl ConfigDef {
already_no_default = true;
},
(PalletAttrType::NoBounds(_), _) => {
if !enable_default {
return Err(syn::Error::new(
pallet_attr._bracket.span.join(),
"`#[pallet:no_default_bounds]` can only be used if `#[pallet::config(with_default)]` \
has been specified"
))
}
if already_no_default_bounds {
return Err(syn::Error::new(
pallet_attr._bracket.span.join(),
"Duplicate #[pallet::no_default_bounds] attribute not allowed.",
))
}
already_no_default_bounds = true;
},
}
}
if !already_no_default && !is_event && enable_default {
if !already_no_default && enable_default {
default_sub_trait
.as_mut()
.expect("is 'Some(_)' if 'enable_default'; qed")
.items
.push(trait_item.clone());
.push((trait_item.clone(), already_no_default_bounds));
}
}
+17 -2
View File
@@ -830,6 +830,21 @@ pub mod pallet_prelude {
};
pub use codec::{Decode, Encode, MaxEncodedLen};
pub use frame_support::pallet_macros::*;
/// The optional attribute `#[inject_runtime_type]` can be attached to `RuntimeCall`,
/// `RuntimeEvent`, `RuntimeOrigin` or `PalletInfo` in an impl statement that has
/// `#[register_default_impl]` attached to indicate that this item is generated by
/// `construct_runtime`.
///
/// Attaching this attribute to such an item ensures that the combined impl generated via
/// [`#[derive_impl(..)]`](`macro@super::derive_impl`) will use the correct type
/// auto-generated by `construct_runtime!`.
#[doc = docify::embed!("src/tests/inject_runtime_type.rs", derive_impl_works_with_runtime_type_injection)]
///
/// However, if `no_aggregated_types` is specified while using
/// `[`#[derive_impl(..)]`](`macro@super::derive_impl`)`, then these items are attached
/// verbatim to the combined impl.
#[doc = docify::embed!("src/tests/inject_runtime_type.rs", derive_impl_works_with_no_aggregated_types)]
pub use frame_support_procedural::inject_runtime_type;
pub use frame_support_procedural::register_default_impl;
pub use scale_info::TypeInfo;
pub use sp_inherents::MakeFatalError;
@@ -2176,8 +2191,8 @@ pub mod pallet_macros {
call_index, compact, composite_enum, config, constant,
disable_frame_system_supertrait_check, error, event, extra_constants, generate_deposit,
generate_store, genesis_build, genesis_config, getter, hooks, import_section, inherent,
no_default, origin, pallet_section, storage, storage_prefix, storage_version, type_value,
unbounded, validate_unsigned, weight, whitelist_storage,
no_default, no_default_bounds, origin, pallet_section, storage, storage_prefix,
storage_version, type_value, unbounded, validate_unsigned, weight, whitelist_storage,
};
}
@@ -0,0 +1,47 @@
// 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 super::{Config, Runtime};
use crate::{derive_impl, pallet_prelude::inject_runtime_type};
use static_assertions::assert_type_eq_all;
#[docify::export]
#[test]
fn derive_impl_works_with_runtime_type_injection() {
assert_type_eq_all!(<Runtime as Config>::RuntimeOrigin, super::RuntimeOrigin);
assert_type_eq_all!(<Runtime as Config>::RuntimeCall, super::RuntimeCall);
assert_type_eq_all!(<Runtime as Config>::PalletInfo, super::PalletInfo);
}
#[docify::export]
#[test]
fn derive_impl_works_with_no_aggregated_types() {
struct DummyRuntime;
#[derive_impl(
super::frame_system::config_preludes::TestDefaultConfig as super::frame_system::DefaultConfig,
no_aggregated_types
)]
impl Config for DummyRuntime {
type Block = super::Block;
type AccountId = super::AccountId;
type PalletInfo = super::PalletInfo;
}
assert_type_eq_all!(<DummyRuntime as Config>::RuntimeOrigin, ());
assert_type_eq_all!(<DummyRuntime as Config>::RuntimeCall, ());
}
+26 -6
View File
@@ -25,6 +25,7 @@ use sp_runtime::{generic, traits::BlakeTwo256, BuildStorage};
pub use self::frame_system::{pallet_prelude::*, Config, Pallet};
mod inject_runtime_type;
mod storage_alias;
#[pallet]
@@ -34,17 +35,40 @@ pub mod frame_system {
pub use crate::dispatch::RawOrigin;
use crate::pallet_prelude::*;
pub mod config_preludes {
use super::{inject_runtime_type, DefaultConfig};
pub struct TestDefaultConfig;
#[crate::register_default_impl(TestDefaultConfig)]
impl DefaultConfig for TestDefaultConfig {
type AccountId = u64;
type BaseCallFilter = frame_support::traits::Everything;
#[inject_runtime_type]
type RuntimeOrigin = ();
#[inject_runtime_type]
type RuntimeCall = ();
#[inject_runtime_type]
type PalletInfo = ();
type DbWeight = ();
}
}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::config]
#[pallet::config(with_default)]
#[pallet::disable_frame_system_supertrait_check]
pub trait Config: 'static {
#[pallet::no_default]
type Block: Parameter + sp_runtime::traits::Block;
type AccountId;
#[pallet::no_default_bounds]
type BaseCallFilter: crate::traits::Contains<Self::RuntimeCall>;
#[pallet::no_default_bounds]
type RuntimeOrigin;
#[pallet::no_default_bounds]
type RuntimeCall;
#[pallet::no_default_bounds]
type PalletInfo: crate::traits::PalletInfo;
type DbWeight: Get<crate::weights::RuntimeDbWeight>;
}
@@ -168,14 +192,10 @@ crate::construct_runtime!(
}
);
#[crate::derive_impl(self::frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
impl Config for Runtime {
type Block = Block;
type AccountId = AccountId;
type BaseCallFilter = crate::traits::Everything;
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type PalletInfo = PalletInfo;
type DbWeight = ();
}
fn new_test_ext() -> TestExternalities {
@@ -0,0 +1,23 @@
use frame_support::{*, pallet_prelude::inject_runtime_type};
use static_assertions::assert_type_eq_all;
pub trait Config {
type RuntimeCall;
}
struct Pallet;
#[register_default_impl(Pallet)]
impl Config for Pallet {
#[inject_runtime_type]
type RuntimeCall = ();
}
struct SomePallet;
#[derive_impl(Pallet)] // Injects type RuntimeCall = RuntimeCall;
impl Config for SomePallet {}
assert_type_eq_all!(<SomePallet as Config>::RuntimeCall, u32);
fn main() {}
@@ -0,0 +1,10 @@
error[E0412]: cannot find type `RuntimeCall` in this scope
--> tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.rs:13:10
|
13 | type RuntimeCall = ();
| ^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeCall`
...
18 | #[derive_impl(Pallet)] // Injects type RuntimeCall = RuntimeCall;
| ---------------------- in this macro invocation
|
= note: this error originates in the macro `__export_tokens_tt_pallet` which comes from the expansion of the macro `frame_support::macro_magic::forward_tokens` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -0,0 +1,25 @@
use frame_support::{*, pallet_prelude::inject_runtime_type};
use static_assertions::assert_type_eq_all;
pub trait Config {
type RuntimeInfo;
}
type RuntimeInfo = u32;
struct Pallet;
#[register_default_impl(Pallet)]
impl Config for Pallet {
#[inject_runtime_type]
type RuntimeInfo = ();
}
struct SomePallet;
#[derive_impl(Pallet)] // Injects type RuntimeInfo = RuntimeInfo;
impl Config for SomePallet {}
assert_type_eq_all!(<SomePallet as Config>::RuntimeInfo, u32);
fn main() {}
@@ -0,0 +1,14 @@
error: `#[inject_runtime_type]` can only be attached to `RuntimeCall`, `RuntimeEvent`, `RuntimeOrigin` or `PalletInfo`
--> tests/derive_impl_ui/inject_runtime_type_invalid.rs:15:5
|
15 | type RuntimeInfo = ();
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0046]: not all trait items implemented, missing: `RuntimeInfo`
--> tests/derive_impl_ui/inject_runtime_type_invalid.rs:13:1
|
5 | type RuntimeInfo;
| ---------------- `RuntimeInfo` from trait
...
13 | impl Config for Pallet {
| ^^^^^^^^^^^^^^^^^^^^^^ missing `RuntimeInfo` in implementation
@@ -0,0 +1,25 @@
use frame_support::{*, pallet_prelude::inject_runtime_type};
use static_assertions::assert_type_eq_all;
pub trait Config {
type RuntimeCall;
}
type RuntimeCall = u32;
struct Pallet;
#[register_default_impl(Pallet)]
impl Config for Pallet {
#[inject_runtime_type]
type RuntimeCall = ();
}
struct SomePallet;
#[derive_impl(Pallet)] // Injects type RuntimeCall = RuntimeCall;
impl Config for SomePallet {}
assert_type_eq_all!(<SomePallet as Config>::RuntimeCall, u32);
fn main() {}
@@ -5,7 +5,7 @@ mod pallet {
#[pallet::config(with_default)]
pub trait Config: frame_system::Config {
#[pallet::constant]
type MyGetParam2: Get<Self::RuntimeCall>;
type MyGetParam2: Get<Self::Block>;
}
#[pallet::pallet]
@@ -1,5 +1,5 @@
error[E0220]: associated type `RuntimeCall` not found for `Self`
error[E0220]: associated type `Block` not found for `Self`
--> tests/pallet_ui/default_config_with_no_default_in_system.rs:8:31
|
8 | type MyGetParam2: Get<Self::RuntimeCall>;
| ^^^^^^^^^^^ associated type `RuntimeCall` not found
8 | type MyGetParam2: Get<Self::Block>;
| ^^^^^ there is a similarly named associated type `Block` in the trait `frame_system::Config`
@@ -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_bounds]
type MyGetParam2: Get<u32>;
}
#[pallet::pallet]
pub struct Pallet<T>(core::marker::PhantomData<T>);
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
#[pallet::call]
impl<T: Config> Pallet<T> {}
}
fn main() {}
@@ -0,0 +1,5 @@
error: `#[pallet:no_default_bounds]` can only be used if `#[pallet::config(with_default)]` has been specified
--> tests/pallet_ui/no_default_bounds_but_missing_with_default.rs:9:4
|
9 | #[pallet::no_default_bounds]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+21 -7
View File
@@ -205,7 +205,7 @@ pub mod pallet {
/// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`].
pub mod config_preludes {
use super::DefaultConfig;
use super::{inject_runtime_type, DefaultConfig};
/// Provides a viable default config that can be used with
/// [`derive_impl`](`frame_support::derive_impl`) to derive a testing pallet config
@@ -232,6 +232,17 @@ pub mod pallet {
type BlockWeights = ();
type BlockLength = ();
type DbWeight = ();
#[inject_runtime_type]
type RuntimeEvent = ();
#[inject_runtime_type]
type RuntimeOrigin = ();
#[inject_runtime_type]
type RuntimeCall = ();
#[inject_runtime_type]
type PalletInfo = ();
type BaseCallFilter = frame_support::traits::Everything;
type BlockHashCount = frame_support::traits::ConstU64<10>;
type OnSetCode = ();
}
}
@@ -240,6 +251,7 @@ pub mod pallet {
#[pallet::disable_frame_system_supertrait_check]
pub trait Config: 'static + Eq + Clone {
/// The aggregated event type of the runtime.
#[pallet::no_default_bounds]
type RuntimeEvent: Parameter
+ Member
+ From<Event<Self>>
@@ -256,7 +268,7 @@ pub mod pallet {
/// [`frame_support::traits::InsideBoth`], [`frame_support::traits::TheseExcept`] or
/// [`frame_support::traits::EverythingBut`] et al. The default would be
/// [`frame_support::traits::Everything`].
#[pallet::no_default]
#[pallet::no_default_bounds]
type BaseCallFilter: Contains<Self::RuntimeCall>;
/// Block & extrinsics weights: base values and limits.
@@ -268,14 +280,14 @@ pub mod pallet {
type BlockLength: Get<limits::BlockLength>;
/// The `RuntimeOrigin` type used by dispatchable calls.
#[pallet::no_default]
#[pallet::no_default_bounds]
type RuntimeOrigin: Into<Result<RawOrigin<Self::AccountId>, Self::RuntimeOrigin>>
+ From<RawOrigin<Self::AccountId>>
+ Clone
+ OriginTrait<Call = Self::RuntimeCall, AccountId = Self::AccountId>;
/// The aggregated `RuntimeCall` type.
#[pallet::no_default]
#[pallet::no_default_bounds]
type RuntimeCall: Parameter
+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>
+ Debug
@@ -335,7 +347,7 @@ pub mod pallet {
/// Maximum number of block number to block hash mappings to keep (oldest pruned first).
#[pallet::constant]
#[pallet::no_default]
#[pallet::no_default_bounds]
type BlockHashCount: Get<BlockNumberFor<Self>>;
/// The weight of runtime database operations the runtime can invoke.
@@ -350,7 +362,9 @@ pub mod pallet {
///
/// Expects the `PalletInfo` type that is being generated by `construct_runtime!` in the
/// runtime.
#[pallet::no_default]
///
/// For tests it is okay to use `()` as type, however it will provide "useless" data.
#[pallet::no_default_bounds]
type PalletInfo: PalletInfo;
/// Data to be associated with an account (other than nonce/transaction counter, which this
@@ -382,7 +396,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]
#[pallet::no_default_bounds]
type OnSetCode: SetCode<Self>;
/// The maximum number of consumers allowed on a single account.