mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 12:17:58 +00:00
codegen: Add codegen error (#841)
* codegen: Add codegen error Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Use codegen error instead of aborts Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Remove `proc-macro-error` dependency Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * macro/subxt: Transform codegen error into compile_error! Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * cli: Pretty printing for `CodegenError` Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update cargo.lock Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * tests: Adjust testing for codegen error Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Fix documentation example Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Export `CodegenError` Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Use collect::<Result<_>, _>() Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * cli: Adjust comment regarding error printing Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Improve error messages Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> --------- Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::api::CodegenError;
|
||||
|
||||
use super::{
|
||||
CratePath,
|
||||
Derives,
|
||||
@@ -12,7 +14,6 @@ use super::{
|
||||
TypePath,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use proc_macro_error::abort_call_site;
|
||||
use quote::{
|
||||
format_ident,
|
||||
quote,
|
||||
@@ -52,8 +53,8 @@ impl CompositeDef {
|
||||
type_gen: &TypeGenerator,
|
||||
docs: &[String],
|
||||
crate_path: &CratePath,
|
||||
) -> Self {
|
||||
let mut derives = type_gen.type_derives(ty);
|
||||
) -> Result<Self, CodegenError> {
|
||||
let mut derives = type_gen.type_derives(ty)?;
|
||||
let fields: Vec<_> = fields_def.field_types().collect();
|
||||
|
||||
if fields.len() == 1 {
|
||||
@@ -84,7 +85,7 @@ impl CompositeDef {
|
||||
let name = format_ident!("{}", ident);
|
||||
let docs_token = Some(quote! { #( #[doc = #docs ] )* });
|
||||
|
||||
Self {
|
||||
Ok(Self {
|
||||
name,
|
||||
kind: CompositeDefKind::Struct {
|
||||
derives,
|
||||
@@ -93,7 +94,7 @@ impl CompositeDef {
|
||||
},
|
||||
fields: fields_def,
|
||||
docs: docs_token,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Construct a definition which will generate code for an `enum` variant.
|
||||
@@ -183,9 +184,9 @@ impl CompositeDefFields {
|
||||
fields: &[Field],
|
||||
parent_type_params: &[TypeParameter],
|
||||
type_gen: &TypeGenerator,
|
||||
) -> Self {
|
||||
) -> Result<Self, CodegenError> {
|
||||
if fields.is_empty() {
|
||||
return Self::NoFields
|
||||
return Ok(Self::NoFields)
|
||||
}
|
||||
|
||||
let mut named_fields = Vec::new();
|
||||
@@ -209,17 +210,15 @@ impl CompositeDefFields {
|
||||
}
|
||||
|
||||
if !named_fields.is_empty() && !unnamed_fields.is_empty() {
|
||||
abort_call_site!(
|
||||
"'{}': Fields should either be all named or all unnamed.",
|
||||
name,
|
||||
)
|
||||
return Err(CodegenError::InvalidFields(name.into()))
|
||||
}
|
||||
|
||||
if !named_fields.is_empty() {
|
||||
let res = if !named_fields.is_empty() {
|
||||
Self::Named(named_fields)
|
||||
} else {
|
||||
Self::Unnamed(unnamed_fields)
|
||||
}
|
||||
};
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Returns the set of composite fields.
|
||||
|
||||
@@ -17,7 +17,6 @@ use proc_macro2::{
|
||||
Span,
|
||||
TokenStream,
|
||||
};
|
||||
use proc_macro_error::abort_call_site;
|
||||
use quote::{
|
||||
quote,
|
||||
ToTokens,
|
||||
@@ -30,6 +29,8 @@ use scale_info::{
|
||||
};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::api::CodegenError;
|
||||
|
||||
pub use self::{
|
||||
composite_def::{
|
||||
CompositeDef,
|
||||
@@ -91,7 +92,7 @@ impl<'a> TypeGenerator<'a> {
|
||||
}
|
||||
|
||||
/// Generate a module containing all types defined in the supplied type registry.
|
||||
pub fn generate_types_mod(&self) -> Module {
|
||||
pub fn generate_types_mod(&self) -> Result<Module, CodegenError> {
|
||||
let root_mod_ident = &self.types_mod_ident;
|
||||
let mut root_mod = Module::new(root_mod_ident.clone(), root_mod_ident.clone());
|
||||
|
||||
@@ -127,11 +128,11 @@ impl<'a> TypeGenerator<'a> {
|
||||
self,
|
||||
&self.crate_path,
|
||||
self.should_gen_docs,
|
||||
),
|
||||
)?,
|
||||
);
|
||||
}
|
||||
|
||||
root_mod
|
||||
Ok(root_mod)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
@@ -311,12 +312,11 @@ impl<'a> TypeGenerator<'a> {
|
||||
}
|
||||
|
||||
/// Returns the derives to be applied to a generated type.
|
||||
pub fn type_derives(&self, ty: &Type<PortableForm>) -> Derives {
|
||||
pub fn type_derives(&self, ty: &Type<PortableForm>) -> Result<Derives, CodegenError> {
|
||||
let joined_path = ty.path().segments().join("::");
|
||||
let ty_path: syn::TypePath = syn::parse_str(&joined_path).unwrap_or_else(|e| {
|
||||
abort_call_site!("'{}' is an invalid type path: {:?}", joined_path, e,)
|
||||
});
|
||||
self.derives.resolve(&ty_path)
|
||||
let ty_path: syn::TypePath = syn::parse_str(&joined_path)
|
||||
.map_err(|e| CodegenError::InvalidTypePath(joined_path, e))?;
|
||||
Ok(self.derives.resolve(&ty_path))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::CratePath;
|
||||
use proc_macro_error::abort;
|
||||
use crate::{
|
||||
api::CodegenError,
|
||||
CratePath,
|
||||
};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
@@ -106,39 +108,48 @@ impl TypeSubstitutes {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extend(&mut self, elems: impl IntoIterator<Item = (syn::Path, AbsolutePath)>) {
|
||||
self.substitutes
|
||||
.extend(elems.into_iter().map(|(path, AbsolutePath(mut with))| {
|
||||
let Some(syn::PathSegment { arguments: src_path_args, ..}) = path.segments.last() else { abort!(path.span(), "Empty path") };
|
||||
let Some(syn::PathSegment { arguments: target_path_args, ..}) = with.segments.last_mut() else { abort!(with.span(), "Empty path") };
|
||||
pub fn extend(
|
||||
&mut self,
|
||||
elems: impl IntoIterator<Item = (syn::Path, AbsolutePath)>,
|
||||
) -> Result<(), CodegenError> {
|
||||
let to_extend = elems.into_iter().map(|(path, AbsolutePath(mut with))| {
|
||||
let Some(syn::PathSegment { arguments: src_path_args, ..}) = path.segments.last() else {
|
||||
return Err(CodegenError::EmptySubstitutePath(path.span()))
|
||||
};
|
||||
let Some(syn::PathSegment { arguments: target_path_args, ..}) = with.segments.last_mut() else {
|
||||
return Err(CodegenError::EmptySubstitutePath(with.span()))
|
||||
};
|
||||
|
||||
let source_args: Vec<_> = type_args(src_path_args).collect();
|
||||
let source_args: Vec<_> = type_args(src_path_args).collect();
|
||||
|
||||
let param_mapping = if source_args.is_empty() {
|
||||
// If the type parameters on the source type are not specified, then this means that
|
||||
// the type is either not generic or the user wants to pass through all the parameters
|
||||
TypeParamMapping::None
|
||||
} else {
|
||||
// Describe the mapping in terms of "which source param idx is used for each target param".
|
||||
// So, for each target param, find the matching source param index.
|
||||
let mapping = type_args(target_path_args)
|
||||
.filter_map(|arg|
|
||||
source_args
|
||||
.iter()
|
||||
.position(|&src| src == arg)
|
||||
.map(|src_idx|
|
||||
u8::try_from(src_idx).expect("type arguments to be fewer than 256; qed"),
|
||||
)
|
||||
).collect();
|
||||
TypeParamMapping::Specified(mapping)
|
||||
};
|
||||
let param_mapping = if source_args.is_empty() {
|
||||
// If the type parameters on the source type are not specified, then this means that
|
||||
// the type is either not generic or the user wants to pass through all the parameters
|
||||
TypeParamMapping::None
|
||||
} else {
|
||||
// Describe the mapping in terms of "which source param idx is used for each target param".
|
||||
// So, for each target param, find the matching source param index.
|
||||
let mapping = type_args(target_path_args)
|
||||
.filter_map(|arg|
|
||||
source_args
|
||||
.iter()
|
||||
.position(|&src| src == arg)
|
||||
.map(|src_idx|
|
||||
u8::try_from(src_idx).expect("type arguments to be fewer than 256; qed"),
|
||||
)
|
||||
).collect();
|
||||
TypeParamMapping::Specified(mapping)
|
||||
};
|
||||
|
||||
// NOTE: Params are late bound and held separately, so clear them
|
||||
// here to not mess pretty printing this path and params together
|
||||
*target_path_args = syn::PathArguments::None;
|
||||
// NOTE: Params are late bound and held separately, so clear them
|
||||
// here to not mess pretty printing this path and params together
|
||||
*target_path_args = syn::PathArguments::None;
|
||||
|
||||
(PathSegments::from(&path), Substitute { path: with, param_mapping })
|
||||
}));
|
||||
Ok((PathSegments::from(&path), Substitute { path: with, param_mapping }))
|
||||
}).collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
self.substitutes.extend(to_extend);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Given a source type path, return a substituted type path if a substitution is defined.
|
||||
|
||||
+20
-20
@@ -48,7 +48,7 @@ fn generate_struct_with_primitives() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -97,7 +97,7 @@ fn generate_struct_with_a_struct_field() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -145,7 +145,7 @@ fn generate_tuple_struct() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -230,7 +230,7 @@ fn derive_compact_as_for_uint_wrapper_structs() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -297,7 +297,7 @@ fn generate_enum() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -358,7 +358,7 @@ fn compact_fields() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -417,7 +417,7 @@ fn compact_generic_parameter() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -461,7 +461,7 @@ fn generate_array_field() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -501,7 +501,7 @@ fn option_fields() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -544,7 +544,7 @@ fn box_fields_struct() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -587,7 +587,7 @@ fn box_fields_enum() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -630,7 +630,7 @@ fn range_fields() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -677,7 +677,7 @@ fn generics() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -728,7 +728,7 @@ fn generics_nested() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -782,7 +782,7 @@ fn generate_bitvec() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -838,7 +838,7 @@ fn generics_with_alias_adds_phantom_data_marker() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -901,7 +901,7 @@ fn modules() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -961,7 +961,7 @@ fn dont_force_struct_names_camel_case() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -1005,7 +1005,7 @@ fn apply_user_defined_derives_for_all_types() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -1073,7 +1073,7 @@ fn apply_user_defined_derives_for_specific_types() {
|
||||
crate_path,
|
||||
true,
|
||||
);
|
||||
let types = type_gen.generate_types_mod();
|
||||
let types = type_gen.generate_types_mod().expect("Valid type mod; qed");
|
||||
let tests_mod = get_mod(&types, MOD_PATH).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::api::CodegenError;
|
||||
|
||||
use super::{
|
||||
CompositeDef,
|
||||
CompositeDefFields,
|
||||
@@ -46,8 +48,8 @@ impl TypeDefGen {
|
||||
type_gen: &TypeGenerator,
|
||||
crate_path: &CratePath,
|
||||
should_gen_docs: bool,
|
||||
) -> Self {
|
||||
let derives = type_gen.type_derives(ty);
|
||||
) -> Result<Self, CodegenError> {
|
||||
let derives = type_gen.type_derives(ty)?;
|
||||
|
||||
let type_params = ty
|
||||
.type_params()
|
||||
@@ -78,7 +80,7 @@ impl TypeDefGen {
|
||||
composite.fields(),
|
||||
type_params.params(),
|
||||
type_gen,
|
||||
);
|
||||
)?;
|
||||
type_params.update_unused(fields.field_types());
|
||||
let docs = should_gen_docs.then_some(ty.docs()).unwrap_or_default();
|
||||
let composite_def = CompositeDef::struct_def(
|
||||
@@ -90,11 +92,12 @@ impl TypeDefGen {
|
||||
type_gen,
|
||||
docs,
|
||||
crate_path,
|
||||
);
|
||||
)?;
|
||||
TypeDefGenKind::Struct(composite_def)
|
||||
}
|
||||
TypeDef::Variant(variant) => {
|
||||
let type_name = ty.path().ident().expect("variants should have a name");
|
||||
|
||||
let variants = variant
|
||||
.variants()
|
||||
.iter()
|
||||
@@ -104,15 +107,15 @@ impl TypeDefGen {
|
||||
v.fields(),
|
||||
type_params.params(),
|
||||
type_gen,
|
||||
);
|
||||
)?;
|
||||
type_params.update_unused(fields.field_types());
|
||||
let docs =
|
||||
should_gen_docs.then_some(v.docs()).unwrap_or_default();
|
||||
let variant_def =
|
||||
CompositeDef::enum_variant_def(v.name(), fields, docs);
|
||||
(v.index(), variant_def)
|
||||
Ok((v.index(), variant_def))
|
||||
})
|
||||
.collect();
|
||||
.collect::<Result<Vec<_>, CodegenError>>()?;
|
||||
|
||||
TypeDefGenKind::Enum(type_name, variants)
|
||||
}
|
||||
@@ -124,12 +127,12 @@ impl TypeDefGen {
|
||||
.then_some(quote! { #( #[doc = #docs ] )* })
|
||||
.unwrap_or_default();
|
||||
|
||||
Self {
|
||||
Ok(Self {
|
||||
type_params,
|
||||
derives,
|
||||
ty_kind,
|
||||
ty_docs,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user