Default Pallet Config Trait / derive_impl (#13454)

* first draft, probably won't work

* first draft, probably won't work

* good progress..

* good milestone, still a lot to do.

* EVERYTHING WORKS

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

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

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

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* clean up + cargo fmt

* import tokens WIP

* export_tokens working with impl Trait

* WIP / notes

* use macro_magic 0.2.0's export_tokens to access foreign items

* token importing working properly using macro_magic 0.2.5

* combine_impls almost working

* successfully get foreign path via macro_magic 0.2.6

* combine_impls using implementing_type generics

* working + clean up

* more clean up

* decrease rightwards drift and add docs to combine_impls

* add support for macros to impl_item_ident in case we hit that

* add docs for impl_item_ident method

* fix no_std issues

* re-export of macro_magic working in pallets 🎉

* clean up + fully resolve no_std issue with macro_magic with v0.2.11

* remove trait item code for different trait item types since this
is now handled directly by combine_impls

* clean up

* remove dev comments

* only generate default trait if #[pallet::default_trait] is attached

* authorship and most other pallets now compiling

* compiling 🎉

* add check for more than two pallet attributes on Config trait

* remove unused import in nomination-pool

* clean up debug code

* upgrade to macro_magic v0.2.12

* add neater #[register_default_config(SomeIdent)] macro

* really just a thin wrapper around #[export_tokens]

* upgrade to macro_magic 0.3.1

* rewrite parsing to be compatible with syn 2.x, compiling 🎉

* remove unused keywords

* macro stubs for the new pallet:: macros, preliminary docs

* upgrade to macro_magic v0.3.2

* rename register_default_config => register_default_impl

* bump to macro_magic v0.3.3

* custom disambiguation_path working as 2nd arg to derive_impl

* overhaul docs

* fixes, ident-style paths shortcut working

* remove ident-style shortcut because it makes testing difficult

* add passing UI tests for derive_impl

* switch to `ForeignPath as DisambiguationPath` syntax + update docs

* add UI test for bad foreign path

* add UI test for bad disambiguation path

* add UI test for missing disambiguation path

* add UI test for attached to non impl

* fix derive_impl_attr_args_parsing test

* move tests to bottom

* fix nightly issue

* add doc notes on importing/re-exporting

* remove explicit use of macro_magic::use_attr

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

* use explicit macro_magic::use_attr

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

* remove unneeded {}

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

* remove unneeded collect

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

* add docs for TestDefaultConfig

* remove unneeded `#[export_tokens]` on `DefaultConfig`

* add docs for auto-generated `DefaultConfig`

* no need to clone

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

* clean up combine_impls + compiling again

* remove unused dependency

* simplify struct definition

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

* fix register_default_impl docs

* reduce rightward drift / refactor

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

* fix derive_impl after keith's changes

* simplify disambiguation_path calculation

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

* compiling again

* simplify parsing of trait item

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

* rename preludes => prelude

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

* fix other places where we used preludes instead of prelude

* fix indents

* simplify PalletAttr parsing

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

* go back to having no_default and constant as keywords

* make it more clear that disambiguation_path is optional

* make default_trait_items just a Vec instead of Option<Vec>

* rename foreign_path => default_impl_path within substrate

* fix docs

* Change {} to ;

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

* highlight full end-to-end example with link

* add pallet-default-config-example, start by copying dev mode code

* update dev-mode specific docs

* use Person and Points instead of Dummy and Bar

* add docs to example pallet

* revert changes to pallets other than the default config example

* fix outdated references to basic example pallet

* re-order docs to be a bit more clear

* better errors for extra attributes

* add UI tests for duplicate/extra attributes on trait items

* 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

* add note about new optional conventions

* improve docs about `DefaultConfig` and link to these from a few places

* fix doc comment

* fix old comment referencing `pallet::default_config`

* use u32 instead of u64 for block number

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* use () instead of u32 for `AccountData`

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* use ConstU32<10> for BlockHashCount instead of ConstU64<10>

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* people are not dummies

Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>

* fix wording

Co-authored-by: Just van Stam <vstam1@users.noreply.github.com>

* Person => People and compiling again

* add docs for `prelude` module in frame_system

* update Cargo.lock

* cleaner example

* tweaks

* update docs more

* update docs more

* update docs more

* update docs more

* fix ui tests

* err

* Update frame/support/test/tests/pallet_ui.rs

* update ui tests

---------

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Sam Johnson <sam@durosoft.com>
Co-authored-by: parity-processbot <>
Co-authored-by: Bastian Köcher <git@kchr.de>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>
Co-authored-by: Just van Stam <vstam1@users.noreply.github.com>
This commit is contained in:
Kian Paimani
2023-05-30 10:06:40 +02:00
committed by GitHub
parent a8edaf47d5
commit 263a5d6c1e
35 changed files with 1445 additions and 80 deletions
@@ -0,0 +1,38 @@
// 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)]
#[rustversion::attr(not(stable), ignore)]
#[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");
}
@@ -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<bool>;
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() {}
@@ -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)
@@ -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<bool>;
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() {}
@@ -0,0 +1,7 @@
error: cannot find macro `__export_tokens_tt_tiger` in this scope
--> tests/derive_impl_ui/bad_default_impl_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)
@@ -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<bool>;
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() {}
@@ -0,0 +1,16 @@
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)]
25 | | impl Animal for FourLeggedAnimal {
26 | | type Locomotion = RunsOnFourLegs;
27 | | type Diet = Omnivore;
... |
37 | |
38 | | #[derive_impl(FourLeggedAnimal as Insect)]
| | -----------------------------------------^
| |_|________________________________________|
| | 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)
@@ -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<bool>;
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() {}
@@ -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)
@@ -0,0 +1,69 @@
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 Nocturnal = Option<bool>;
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 {}
// without omitting the `as X`
#[derive_impl(FourLeggedAnimal as Animal)]
impl Animal for AcquaticMammal {
type Locomotion = (Swims, RunsOnFourLegs);
type Environment = (Land, Sea);
}
assert_type_eq_all!(<AcquaticMammal as Animal>::Locomotion, (Swims, RunsOnFourLegs));
assert_type_eq_all!(<AcquaticMammal as Animal>::Environment, (Land, Sea));
assert_type_eq_all!(<AcquaticMammal as Animal>::Diet, Omnivore);
assert_type_eq_all!(<AcquaticMammal as Animal>::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!(<Lion as Animal>::Diet, Carnivore);
assert_type_eq_all!(<Lion as Animal>::SleepingStrategy, Nocturnal);
assert_type_eq_all!(<Lion as Animal>::Environment, Land);
assert_type_eq_all!(<Lion as Animal>::Locomotion, RunsOnFourLegs);
fn main() {}
@@ -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
}
@@ -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<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]` 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]
| ^^^^^^^^^^^^^^^^^^^^
@@ -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;
| ^^^^^
@@ -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<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: Duplicate #[pallet::constant] attribute not allowed.
--> tests/pallet_ui/trait_item_duplicate_constant_attr.rs:9:4
|
9 | #[pallet::constant]
| ^^^^^^^^^^^^^^^^^^
@@ -0,0 +1,24 @@
#[frame_support::pallet]
mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
#[pallet::config(with_default)]
pub trait Config: frame_system::Config {
#[pallet::constant]
#[pallet::no_default]
#[pallet::no_default]
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: Duplicate #[pallet::no_default] attribute not allowed.
--> tests/pallet_ui/trait_item_duplicate_no_default.rs:10:4
|
10 | #[pallet::no_default]
| ^^^^^^^^^^^^^^^^^^^^