Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

frame/proc-macro: Refactor code for better readability #4712

Merged
merged 8 commits into from
Jun 8, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ struct ConstDef {
pub metadata_name: Option<syn::Ident>,
}

///
/// * Impl fn module_constant_metadata for pallet.
/// Implement the `pallet_constants_metadata` function for the pallet.
pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream {
let frame_support = &def.frame_support;
let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site());
Expand Down
128 changes: 61 additions & 67 deletions substrate/frame/support/procedural/src/pallet/parse/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,30 +94,26 @@ impl TryFrom<&syn::TraitItemType> for ConstMetadataDef {
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
}
.find_map(|param_bound| {
let syn::TypeParamBound::Trait(trait_bound) = param_bound else { return None };

trait_bound.path.segments.last().and_then(|s| (s.ident == "Get").then(|| s))
})
.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 syn::PathArguments::AngleBracketed(ref ab) = bound.arguments else {
return Err(err(bound.span(), "Expected trait generic args"))
};

// Only one type argument is expected.
if ab.args.len() != 1 {
return Err(err(bound.span(), "Expected a single type argument"))
}

let syn::GenericArgument::Type(ref type_arg) = ab.args[0] else {
return Err(err(ab.args[0].span(), "Expected a type argument"))
};

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");

Expand Down Expand Up @@ -223,55 +219,55 @@ fn check_event_type(
trait_item: &syn::TraitItem,
trait_has_instance: bool,
) -> syn::Result<bool> {
if let syn::TraitItem::Type(type_) = trait_item {
if type_.ident == "RuntimeEvent" {
// Check event has no generics
if !type_.generics.params.is_empty() || type_.generics.where_clause.is_some() {
let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must have\
no generics nor where_clause";
return Err(syn::Error::new(trait_item.span(), msg))
}
let syn::TraitItem::Type(type_) = trait_item else { return Ok(false) };

// Check bound contains IsType and From
let has_is_type_bound = type_.bounds.iter().any(|s| {
syn::parse2::<IsTypeBoundEventParse>(s.to_token_stream())
.map_or(false, |b| has_expected_system_config(b.0, frame_system))
});

if !has_is_type_bound {
let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \
bound: `IsType<<Self as frame_system::Config>::RuntimeEvent>`".to_string();
return Err(syn::Error::new(type_.span(), msg))
}
if type_.ident != "RuntimeEvent" {
return Ok(false)
}

let from_event_bound = type_
.bounds
.iter()
.find_map(|s| syn::parse2::<FromEventParse>(s.to_token_stream()).ok());
// Check event has no generics
if !type_.generics.params.is_empty() || type_.generics.where_clause.is_some() {
let msg =
"Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must have\
no generics nor where_clause";
return Err(syn::Error::new(trait_item.span(), msg))
}

let from_event_bound = if let Some(b) = from_event_bound {
b
} else {
let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \
bound: `From<Event>` or `From<Event<Self>>` or `From<Event<Self, I>>`";
return Err(syn::Error::new(type_.span(), msg))
};
// Check bound contains IsType and From
let has_is_type_bound = type_.bounds.iter().any(|s| {
syn::parse2::<IsTypeBoundEventParse>(s.to_token_stream())
.map_or(false, |b| has_expected_system_config(b.0, frame_system))
});

if !has_is_type_bound {
let msg =
"Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \
bound: `IsType<<Self as frame_system::Config>::RuntimeEvent>`"
.to_string();
return Err(syn::Error::new(type_.span(), msg))
}

if from_event_bound.is_generic && (from_event_bound.has_instance != trait_has_instance)
{
let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` bounds inconsistent \
let from_event_bound = type_
.bounds
.iter()
.find_map(|s| syn::parse2::<FromEventParse>(s.to_token_stream()).ok());

let Some(from_event_bound) = from_event_bound else {
let msg =
"Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \
bound: `From<Event>` or `From<Event<Self>>` or `From<Event<Self, I>>`";
return Err(syn::Error::new(type_.span(), msg))
};

if from_event_bound.is_generic && (from_event_bound.has_instance != trait_has_instance) {
let msg =
"Invalid `type RuntimeEvent`, associated type `RuntimeEvent` bounds inconsistent \
`From<Event..>`. Config and generic Event must be both with instance or \
without instance";
return Err(syn::Error::new(type_.span(), msg))
}

Ok(true)
} else {
Ok(false)
}
} else {
Ok(false)
return Err(syn::Error::new(type_.span(), msg))
}

Ok(true)
}

/// Check that the path to `frame_system::Config` is valid, this is that the path is just
Expand Down Expand Up @@ -334,9 +330,7 @@ impl ConfigDef {
item: &mut syn::Item,
enable_default: bool,
) -> syn::Result<Self> {
let item = if let syn::Item::Trait(item) = item {
item
} else {
let syn::Item::Trait(item) = item else {
let msg = "Invalid pallet::config, expected trait definition";
return Err(syn::Error::new(item.span(), msg))
};
Expand Down
16 changes: 8 additions & 8 deletions substrate/frame/support/procedural/src/pallet/parse/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ pub(crate) fn take_first_item_pallet_attr<Attr>(
where
Attr: syn::parse::Parse,
{
let attrs = if let Some(attrs) = item.mut_item_attrs() { attrs } else { return Ok(None) };
let Some(attrs) = item.mut_item_attrs() else { return Ok(None) };

if let Some(index) = attrs.iter().position(|attr| {
let Some(index) = attrs.iter().position(|attr| {
attr.path().segments.first().map_or(false, |segment| segment.ident == "pallet")
}) {
let pallet_attr = attrs.remove(index);
Ok(Some(syn::parse2(pallet_attr.into_token_stream())?))
} else {
Ok(None)
}
}) else {
return Ok(None)
};

let pallet_attr = attrs.remove(index);
Ok(Some(syn::parse2(pallet_attr.into_token_stream())?))
}

/// Take all the pallet attributes (e.g. attribute like `#[pallet..]`) and decode them to `Attr`
Expand Down
Loading