Skip to content

Commit

Permalink
DispatchError::Module is now a tuple variant in latest Substrate (#439)
Browse files Browse the repository at this point in the history
* ModuleError is now a tuple variant

* more robust pointer to DispatchError

* backward compat

* clippy

* cargo fmt

* abort_call_site and simplify path comparison

* clippy
  • Loading branch information
jsdw authored Feb 15, 2022
1 parent 117e2ed commit cb9177a
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 11 deletions.
77 changes: 67 additions & 10 deletions codegen/src/api/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ use proc_macro2::{
Span as Span2,
TokenStream as TokenStream2,
};
use proc_macro_error::abort_call_site;
use quote::quote;
use scale_info::TypeDef;

/// Tokens which allow us to provide static error information in the generated output.
pub struct ErrorDetails {
Expand Down Expand Up @@ -71,17 +73,48 @@ pub fn generate_error_details(metadata: &RuntimeMetadataV14) -> ErrorDetails {
}
});

ErrorDetails {
type_def: quote! {
pub struct ErrorDetails {
pub pallet: &'static str,
pub error: &'static str,
pub docs: &'static str,
}
},
dispatch_error_impl_fn: quote! {
let dispatch_error_def = metadata
.types
.types()
.iter()
.find(|&ty| ty.ty().path().segments() == ["sp_runtime", "DispatchError"])
.unwrap_or_else(|| {
abort_call_site!("sp_runtime::DispatchError type expected in metadata")
})
.ty()
.type_def();

// Slightly older versions of substrate have a `DispatchError::Module { index, error }`
// variant. Newer versions have something like a `DispatchError::Module (Details)` variant.
// We check to see which type of variant we're dealing with based on the metadata, and
// generate the correct code to handle either older or newer substrate versions.
let module_variant_is_struct = if let TypeDef::Variant(details) = dispatch_error_def {
let module_variant = details
.variants()
.iter()
.find(|variant| variant.name() == "Module")
.unwrap_or_else(|| {
abort_call_site!("DispatchError::Module variant expected in metadata")
});
let are_fields_named = module_variant
.fields()
.get(0)
.unwrap_or_else(|| {
abort_call_site!(
"DispatchError::Module expected to contain 1 or more fields"
)
})
.name()
.is_some();
are_fields_named
} else {
false
};

let dispatch_error_impl_fn = if module_variant_is_struct {
quote! {
pub fn details(&self) -> Option<ErrorDetails> {
if let Self::Module { index, error } = self {
if let Self::Module { error, index } = self {
match (index, error) {
#( #match_body_items ),*,
_ => None
Expand All @@ -90,7 +123,31 @@ pub fn generate_error_details(metadata: &RuntimeMetadataV14) -> ErrorDetails {
None
}
}
}
} else {
quote! {
pub fn details(&self) -> Option<ErrorDetails> {
if let Self::Module (module_error) = self {
match (module_error.index, module_error.error) {
#( #match_body_items ),*,
_ => None
}
} else {
None
}
}
}
};

ErrorDetails {
type_def: quote! {
pub struct ErrorDetails {
pub pallet: &'static str,
pub error: &'static str,
pub docs: &'static str,
}
},
dispatch_error_impl_fn,
}
}

Expand Down
2 changes: 1 addition & 1 deletion codegen/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ impl RuntimeGenerator {
#types_mod

/// The default error type returned when there is a runtime issue.
pub type DispatchError = self::runtime_types::sp_runtime::DispatchError;
pub type DispatchError = #types_mod_ident::sp_runtime::DispatchError;

// Statically generate error information so that we don't need runtime metadata for it.
#error_type
Expand Down

0 comments on commit cb9177a

Please sign in to comment.