-
Notifications
You must be signed in to change notification settings - Fork 689
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
Metadata V16 (unstable): Enrich metadata with associated types of config traits #5274
Conversation
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
types Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs
Outdated
Show resolved
Hide resolved
Co-authored-by: Guillaume Thiolliere <[email protected]>
Co-authored-by: Guillaume Thiolliere <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
error[E0277]: the trait bound `<T as pallet::Config>::MyNonScaleTypeInfo: TypeInfo` is not satisfied | ||
--> tests/pallet_ui/config_metadata_non_type_info.rs:29:8 | ||
| | ||
29 | type MyNonScaleTypeInfo; | ||
| ^^^^^^^^^^^^^^^^^^ the trait `TypeInfo` is not implemented for `<T as pallet::Config>::MyNonScaleTypeInfo` | ||
| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general I prefer that error originating from expansion from an attribute point directly to the attribute.
Like here it would point to #[pallet::include_metadata]
, instead of the associated type ident.
This allows user to directly look at the doc of include_metadata
and not be confused trying to understand it as a regular rust error.
But in this case I don't know, it is also fine as it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you mean now! Indeed, have added an extra check while collecting the metadata, we should have now a bit clearer error message here:
error: Invalid #[pallet::include_metadata] in #[pallet::config], collected type `MyNonScaleTypeInfo` does not implement `scale::TypeInfo`
--> tests/pallet_ui/config_metadata_non_type_info.rs:28:4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually what I imagine was something like:
let span = /* span of `#[pallet::include_metadata]" or otherwise call site for automatic inclusion*/
quote_spanned(span => /* expansion related to include metadata or automatic inclusion*/)
But everything is good to me, I don't have much opinion.
Your current implementation is more restrictive but more explicit so it can be the best.
Looks good to me, but zombienet tests are failing somehow. |
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
@bkchr could you please have a quick look whenever you have some time? 🙏 Thanks everyone for the reviews here 🙏 |
if !contains_type_info_bound(ty) { | ||
let msg = format!( | ||
"Invalid #[pallet::include_metadata] in #[pallet::config], collected type `{}` \ | ||
does not implement `scale::TypeInfo`", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick, maybe we can say: does not explicitly bound TypeInfo
or Parameter
.
ty.bounds.iter().any(|bound| { | ||
let syn::TypeParamBound::Trait(bound) = bound else { return false }; | ||
|
||
KNOWN_TYPE_INFO_BOUNDS.iter().any(|known| bound.path.is_ident(known)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this will not match scale::TypeInfo
but only TypeInfo
, isn't it?
What I mean is that we do the match on the whole path, not the last segment, no?
If we want to support only this. Then we can say in the error message of include_metadata
something like: "Note: only ident is supported, e.g. scale::TypeInfo
is not detected, only TypeInfo
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should just take the last element of the path to improve the detection?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mainly left some nitpicks. Generally looking good. Good work 👍
} | ||
|
||
if let syn::TraitItem::Type(ref ty) = trait_item { | ||
if !contains_type_info_bound(ty) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we implement here a mix of:
https://docs.rs/static_assertions/1.1.0/src/static_assertions/assert_impl.rs.html#329-356
and
This should give some very nice error message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh but maybe not possible. Not sure, but worth a try.
// | ||
// They must provide a type item that implements `TypeInfo`. | ||
(PalletAttrType::IncludeMetadata(_), syn::TraitItem::Type(ref typ)) => { | ||
already_collected_associated_type = Some(pallet_attr._bracket.span.join()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be an error if the attribute is passed multiple times.
ty.bounds.iter().any(|bound| { | ||
let syn::TypeParamBound::Trait(bound) = bound else { return false }; | ||
|
||
KNOWN_TYPE_INFO_BOUNDS.iter().any(|known| bound.path.is_ident(known)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should just take the last element of the path to improve the detection?
let fields: syn::punctuated::Punctuated<ConfigValue, syn::Token![,]> = | ||
inside_config.parse_terminated(ConfigValue::parse, syn::Token![,])?; | ||
let config_values = fields.iter().collect::<Vec<_>>(); | ||
|
||
let frequencies = config_values.iter().fold(HashMap::new(), |mut map, val| { | ||
let string_name = match val { | ||
ConfigValue::WithDefault(_) => "with_default", | ||
ConfigValue::WithoutAutomaticMetadata(_) => "without_automatic_metadata", | ||
} | ||
.to_string(); | ||
map.entry(string_name).and_modify(|frq| *frq += 1).or_insert(1); | ||
map | ||
}); | ||
let with_default = frequencies.get("with_default").copied().unwrap_or(0) > 0; | ||
let without_automatic_metadata = | ||
frequencies.get("without_automatic_metadata").copied().unwrap_or(0) > 0; | ||
|
||
let duplicates = frequencies | ||
.into_iter() | ||
.filter_map(|(name, frq)| if frq > 1 { Some(name) } else { None }) | ||
.collect::<Vec<_>>(); | ||
if !duplicates.is_empty() { | ||
let msg = format!("Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: {}.", duplicates.join(", ")); | ||
return Err(syn::Error::new(span, msg)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just having some options would be easier here? But yeah, the code works the way it is written.
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
Signed-off-by: Alexandru Vasile <[email protected]>
This feature is part of the upcoming metadata V16. The associated types of the
Config
trait that require theTypeInfo
orParameter
bounds are included in the metadata of the pallet. The metadata is not yet exposed to the end-user, however the metadata intermediate representation (IR) contains these types.Developers can opt out of metadata collection of the associated types by specifying
without_metadata
optional attribute to the#[pallet::config]
.Furthermore, the
without_metadata
argument can be used in combination with the newly added#[pallet::include_metadata]
attribute to selectively include only certain associated types in the metadata collection.API Design
Builds on top of the PoC: #4358
Closes: #4519
cc @paritytech/subxt-team