mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 02:17:58 +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.
|
||||
|
||||
use super::helper;
|
||||
use core::convert::TryFrom;
|
||||
use syn::spanned::Spanned;
|
||||
use quote::ToTokens;
|
||||
|
||||
@@ -25,7 +26,6 @@ mod keyword {
|
||||
syn::custom_keyword!(From);
|
||||
syn::custom_keyword!(T);
|
||||
syn::custom_keyword!(I);
|
||||
syn::custom_keyword!(Get);
|
||||
syn::custom_keyword!(config);
|
||||
syn::custom_keyword!(IsType);
|
||||
syn::custom_keyword!(Event);
|
||||
@@ -62,19 +62,41 @@ pub struct ConstMetadataDef {
|
||||
pub doc: Vec<syn::Lit>,
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for ConstMetadataDef {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let doc = helper::get_doc_literals(&syn::Attribute::parse_outer(input)?);
|
||||
input.parse::<syn::Token![type]>()?;
|
||||
let ident = input.parse::<syn::Ident>()?;
|
||||
input.parse::<syn::Token![:]>()?;
|
||||
input.parse::<keyword::Get>()?;
|
||||
input.parse::<syn::Token![<]>()?;
|
||||
let mut type_ = input.parse::<syn::Type>()?;
|
||||
type_ = syn::parse2::<syn::Type>(replace_self_by_t(type_.to_token_stream()))
|
||||
impl TryFrom<&syn::TraitItemType> for ConstMetadataDef {
|
||||
type Error = syn::Error;
|
||||
|
||||
fn try_from(trait_ty: &syn::TraitItemType) -> Result<Self, Self::Error> {
|
||||
let err = |span, msg|
|
||||
syn::Error::new(span, format!("Invalid usage of `#[pallet::constant]`: {}", msg));
|
||||
let doc = helper::get_doc_literals(&trait_ty.attrs);
|
||||
let ident = trait_ty.ident.clone();
|
||||
let bound = trait_ty.bounds
|
||||
.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");
|
||||
input.parse::<syn::Token![>]>()?;
|
||||
input.parse::<syn::Token![;]>()?;
|
||||
|
||||
Ok(Self { ident, type_, doc })
|
||||
}
|
||||
@@ -322,16 +344,8 @@ impl ConfigDef {
|
||||
|
||||
if type_attrs_const.len() == 1 {
|
||||
match trait_item {
|
||||
syn::TraitItem::Type(type_) => {
|
||||
let constant = syn::parse2::<ConstMetadataDef>(type_.to_token_stream())
|
||||
.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
|
||||
})?;
|
||||
|
||||
syn::TraitItem::Type(ref type_) => {
|
||||
let constant = ConstMetadataDef::try_from(type_)?;
|
||||
consts_metadata.push(constant);
|
||||
},
|
||||
_ => {
|
||||
|
||||
Reference in New Issue
Block a user