mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-23 20:11:06 +00:00
Allow additional trait bounds for #[pallet::constant] (#9050)
* Allow additional trait bounds for constants * Add ui test for constants with additional trait bounds * Update trait constant ui test * Import syn::Error * Use reference instead of cloning * Add extra invalid bound ui test * Out or order valid bounds * Fix ui test * Fix ui test * Apply review suggestion about error message
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use super::helper;
|
use super::helper;
|
||||||
|
use core::convert::TryFrom;
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
|
|
||||||
@@ -25,7 +26,6 @@ mod keyword {
|
|||||||
syn::custom_keyword!(From);
|
syn::custom_keyword!(From);
|
||||||
syn::custom_keyword!(T);
|
syn::custom_keyword!(T);
|
||||||
syn::custom_keyword!(I);
|
syn::custom_keyword!(I);
|
||||||
syn::custom_keyword!(Get);
|
|
||||||
syn::custom_keyword!(config);
|
syn::custom_keyword!(config);
|
||||||
syn::custom_keyword!(IsType);
|
syn::custom_keyword!(IsType);
|
||||||
syn::custom_keyword!(Event);
|
syn::custom_keyword!(Event);
|
||||||
@@ -62,19 +62,41 @@ pub struct ConstMetadataDef {
|
|||||||
pub doc: Vec<syn::Lit>,
|
pub doc: Vec<syn::Lit>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl syn::parse::Parse for ConstMetadataDef {
|
impl TryFrom<&syn::TraitItemType> for ConstMetadataDef {
|
||||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
type Error = syn::Error;
|
||||||
let doc = helper::get_doc_literals(&syn::Attribute::parse_outer(input)?);
|
|
||||||
input.parse::<syn::Token![type]>()?;
|
fn try_from(trait_ty: &syn::TraitItemType) -> Result<Self, Self::Error> {
|
||||||
let ident = input.parse::<syn::Ident>()?;
|
let err = |span, msg|
|
||||||
input.parse::<syn::Token![:]>()?;
|
syn::Error::new(span, format!("Invalid usage of `#[pallet::constant]`: {}", msg));
|
||||||
input.parse::<keyword::Get>()?;
|
let doc = helper::get_doc_literals(&trait_ty.attrs);
|
||||||
input.parse::<syn::Token![<]>()?;
|
let ident = trait_ty.ident.clone();
|
||||||
let mut type_ = input.parse::<syn::Type>()?;
|
let bound = trait_ty.bounds
|
||||||
type_ = syn::parse2::<syn::Type>(replace_self_by_t(type_.to_token_stream()))
|
.iter()
|
||||||
|
.find_map(|b|
|
||||||
|
if let syn::TypeParamBound::Trait(tb) = b {
|
||||||
|
tb.path.segments
|
||||||
|
.last()
|
||||||
|
.and_then(|s| if s.ident == "Get" { Some(s) } else { None } )
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.ok_or_else(|| err(trait_ty.span(), "`Get<T>` trait bound not found"))?;
|
||||||
|
let type_arg = if let syn::PathArguments::AngleBracketed (ref ab) = bound.arguments {
|
||||||
|
if ab.args.len() == 1 {
|
||||||
|
if let syn::GenericArgument::Type(ref ty) = ab.args[0] {
|
||||||
|
Ok(ty)
|
||||||
|
} else {
|
||||||
|
Err(err(ab.args[0].span(), "Expected a type argument"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(err(bound.span(), "Expected a single type argument"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(err(bound.span(), "Expected trait generic args"))
|
||||||
|
}?;
|
||||||
|
let type_ = syn::parse2::<syn::Type>(replace_self_by_t(type_arg.to_token_stream()))
|
||||||
.expect("Internal error: replacing `Self` by `T` should result in valid type");
|
.expect("Internal error: replacing `Self` by `T` should result in valid type");
|
||||||
input.parse::<syn::Token![>]>()?;
|
|
||||||
input.parse::<syn::Token![;]>()?;
|
|
||||||
|
|
||||||
Ok(Self { ident, type_, doc })
|
Ok(Self { ident, type_, doc })
|
||||||
}
|
}
|
||||||
@@ -322,16 +344,8 @@ impl ConfigDef {
|
|||||||
|
|
||||||
if type_attrs_const.len() == 1 {
|
if type_attrs_const.len() == 1 {
|
||||||
match trait_item {
|
match trait_item {
|
||||||
syn::TraitItem::Type(type_) => {
|
syn::TraitItem::Type(ref type_) => {
|
||||||
let constant = syn::parse2::<ConstMetadataDef>(type_.to_token_stream())
|
let constant = ConstMetadataDef::try_from(type_)?;
|
||||||
.map_err(|e| {
|
|
||||||
let error_msg = "Invalid usage of `#[pallet::constant]`, syntax \
|
|
||||||
must be `type $SomeIdent: Get<$SomeType>;`";
|
|
||||||
let mut err = syn::Error::new(type_.span(), error_msg);
|
|
||||||
err.combine(e);
|
|
||||||
err
|
|
||||||
})?;
|
|
||||||
|
|
||||||
consts_metadata.push(constant);
|
consts_metadata.push(constant);
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
@@ -23,4 +23,5 @@ fn pallet_ui() {
|
|||||||
|
|
||||||
let t = trybuild::TestCases::new();
|
let t = trybuild::TestCases::new();
|
||||||
t.compile_fail("tests/pallet_ui/*.rs");
|
t.compile_fail("tests/pallet_ui/*.rs");
|
||||||
|
t.pass("tests/pallet_ui/pass/*.rs");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#[frame_support::pallet]
|
||||||
|
mod pallet {
|
||||||
|
use frame_support::pallet_prelude::*;
|
||||||
|
use frame_system::pallet_prelude::BlockNumberFor;
|
||||||
|
|
||||||
|
#[pallet::config]
|
||||||
|
pub trait Config: frame_system::Config {
|
||||||
|
#[pallet::constant]
|
||||||
|
type U: Get<u32>;
|
||||||
|
|
||||||
|
#[pallet::constant]
|
||||||
|
type V: Get<u32> + From<u16>;
|
||||||
|
|
||||||
|
#[pallet::constant]
|
||||||
|
type W: From<u16> + 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() {
|
||||||
|
}
|
||||||
@@ -1,11 +1,5 @@
|
|||||||
error: Invalid usage of `#[pallet::constant]`, syntax must be `type $SomeIdent: Get<$SomeType>;`
|
error: Invalid usage of `#[pallet::constant]`: `Get<T>` trait bound not found
|
||||||
--> $DIR/trait_constant_invalid_bound.rs:9:3
|
--> $DIR/trait_constant_invalid_bound.rs:9:3
|
||||||
|
|
|
|
||||||
9 | type U;
|
9 | type U;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: expected `:`
|
|
||||||
--> $DIR/trait_constant_invalid_bound.rs:9:9
|
|
||||||
|
|
|
||||||
9 | type U;
|
|
||||||
| ^
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#[frame_support::pallet]
|
||||||
|
mod pallet {
|
||||||
|
use frame_support::pallet_prelude::Hooks;
|
||||||
|
use frame_system::pallet_prelude::BlockNumberFor;
|
||||||
|
|
||||||
|
#[pallet::config]
|
||||||
|
pub trait Config: frame_system::Config {
|
||||||
|
#[pallet::constant]
|
||||||
|
type U: Get<'static>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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() {
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
error: Invalid usage of `#[pallet::constant]`: Expected a type argument
|
||||||
|
--> $DIR/trait_constant_invalid_bound_lifetime.rs:9:15
|
||||||
|
|
|
||||||
|
9 | type U: Get<'static>;
|
||||||
|
| ^^^^^^^
|
||||||
Reference in New Issue
Block a user