git.delta.rocks / unique-network / refs/commits / a1ef1e7a88a7

difftreelog

reafactor: Better error reporting

Trubnikov Sergey2022-11-23parent: #11dcf7d.patch.diff
in: master

2 files changed

modifiedcrates/evm-coder/procedural/src/abi_derive.rsdiffbeforeafterboth
--- a/crates/evm-coder/procedural/src/abi_derive.rs
+++ b/crates/evm-coder/procedural/src/abi_derive.rs
@@ -2,129 +2,151 @@
 
 pub(crate) fn impl_abi_macro(ast: &syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
 	let name = &ast.ident;
+	match &ast.data {
+		syn::Data::Struct(ds) => expand_struct(ds, ast),
+		syn::Data::Enum(de) => expand_enum(de, ast),
+		syn::Data::Union(_) => Err(syn::Error::new(name.span(), "Unions not supported")),
+	}
+}
 
-	match &ast.data {
-		syn::Data::Struct(ds) => {
-			let docs = extract_docs(&ast.attrs)?;
-			let (is_named_fields, field_names, field_types, field_docs, params_count) =
-				match ds.fields {
-					syn::Fields::Named(ref fields) => Ok((
-						true,
-						fields.named.iter().enumerate().map(map_field_to_name),
-						fields.named.iter().map(map_field_to_type),
-						fields.named.iter().map(map_field_to_doc),
-						fields.named.len(),
-					)),
-					syn::Fields::Unnamed(ref fields) => Ok((
-						false,
-						fields.unnamed.iter().enumerate().map(map_field_to_name),
-						fields.unnamed.iter().map(map_field_to_type),
-						fields.unnamed.iter().map(map_field_to_doc),
-						fields.unnamed.len(),
-					)),
-					syn::Fields::Unit => {
-						Err(syn::Error::new(name.span(), "Unit structs not supported"))
-					}
-				}?;
+fn expand_struct(
+	ds: &syn::DataStruct,
+	ast: &syn::DeriveInput,
+) -> syn::Result<proc_macro2::TokenStream> {
+	let name = &ast.ident;
+	let docs = extract_docs(&ast.attrs)?;
+	let (is_named_fields, field_names, field_types, field_docs, params_count) = match ds.fields {
+		syn::Fields::Named(ref fields) => Ok((
+			true,
+			fields.named.iter().enumerate().map(map_field_to_name),
+			fields.named.iter().map(map_field_to_type),
+			fields.named.iter().map(map_field_to_doc),
+			fields.named.len(),
+		)),
+		syn::Fields::Unnamed(ref fields) => Ok((
+			false,
+			fields.unnamed.iter().enumerate().map(map_field_to_name),
+			fields.unnamed.iter().map(map_field_to_type),
+			fields.unnamed.iter().map(map_field_to_doc),
+			fields.unnamed.len(),
+		)),
+		syn::Fields::Unit => Err(syn::Error::new(name.span(), "Unit structs not supported")),
+	}?;
+
+	if params_count == 0 {
+		return Err(syn::Error::new(name.span(), "Empty structs not supported"));
+	};
+
+	let tuple_type = tuple_type(field_types.clone());
+	let tuple_ref_type = tuple_ref_type(field_types.clone());
+	let tuple_data = tuple_data_as_ref(is_named_fields, field_names.clone());
+	let tuple_names = tuple_names(is_named_fields, field_names.clone());
+	let struct_from_tuple = struct_from_tuple(name, is_named_fields, field_names.clone());
+
+	let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);
+	let abi_type = impl_abi_type(name, tuple_type.clone());
+	let abi_read = impl_abi_read(name, tuple_type, tuple_names, struct_from_tuple);
+	let abi_write = impl_abi_write(name, is_named_fields, tuple_ref_type, tuple_data);
+	let solidity_type = impl_solidity_type(name, field_types.clone(), params_count);
+	let solidity_type_name = impl_solidity_type_name(name, field_types.clone(), params_count);
+	let solidity_struct_collect =
+		impl_solidity_struct_collect(name, field_names, field_types, field_docs, &docs)?;
 
-			if params_count == 0 {
-				return Err(syn::Error::new(name.span(), "Empty structs not supported"));
-			};
+	Ok(quote! {
+		#can_be_plcaed_in_vec
+		#abi_type
+		#abi_read
+		#abi_write
+		#solidity_type
+		#solidity_type_name
+		#solidity_struct_collect
+	})
+}
 
-			let tuple_type = tuple_type(field_types.clone());
-			let tuple_ref_type = tuple_ref_type(field_types.clone());
-			let tuple_data = tuple_data_as_ref(is_named_fields, field_names.clone());
-			let tuple_names = tuple_names(is_named_fields, field_names.clone());
-			let struct_from_tuple = struct_from_tuple(name, is_named_fields, field_names.clone());
+fn expand_enum(
+	de: &syn::DataEnum,
+	ast: &syn::DeriveInput,
+) -> syn::Result<proc_macro2::TokenStream> {
+	let name = &ast.ident;
+	check_repr_u8(name, &ast.attrs)?;
+	check_option_validity(de)?;
 
-			let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);
-			let abi_type = impl_abi_type(name, tuple_type.clone());
-			let abi_read = impl_abi_read(name, tuple_type, tuple_names, struct_from_tuple);
-			let abi_write = impl_abi_write(name, is_named_fields, tuple_ref_type, tuple_data);
-			let solidity_type = impl_solidity_type(name, field_types.clone(), params_count);
-			let solidity_type_name =
-				impl_solidity_type_name(name, field_types.clone(), params_count);
-			let solidity_struct_collect =
-				impl_solidity_struct_collect(name, field_names, field_types, field_docs, &docs)?;
+	dbg!(&de);
 
-			Ok(quote! {
-				#can_be_plcaed_in_vec
-				#abi_type
-				#abi_read
-				#abi_write
-				#solidity_type
-				#solidity_type_name
-				#solidity_struct_collect
-			})
-		}
-		syn::Data::Enum(de) => {
-			check_repr_u8(name, &ast.attrs)?;
+	Ok(quote!())
+}
 
-			dbg!(&de);
-			for f in de.variants.iter().filter_map(|v| {
-				if !v.fields.is_empty() {
-					Some(Err(syn::Error::new(
-						v.ident.span(),
-						"Enumeration parameters should not have fields",
-					)))
-				} else if v.discriminant.is_some() {
-					Some(Err(syn::Error::new(
-						v.ident.span(),
-						"Enumeration options should not have an explicit specified value",
-					)))
-				} else {
-					None
-				}
-			}) {
-				f?;
-			}
-			Ok(quote!())
+fn check_option_validity(de: &syn::DataEnum) -> syn::Result<()> {
+	for error in de.variants.iter().filter_map(|v| {
+		if !v.fields.is_empty() {
+			Some(Err(syn::Error::new(
+				v.ident.span(),
+				"Enumeration parameters should not have fields",
+			)))
+		} else if v.discriminant.is_some() {
+			Some(Err(syn::Error::new(
+				v.ident.span(),
+				"Enumeration options should not have an explicit specified value",
+			)))
+		} else {
+			None
 		}
-		syn::Data::Union(_) => Err(syn::Error::new(name.span(), "Unions not supported")),
+	}) {
+		return error;
 	}
+
+	Ok(())
 }
 
 fn check_repr_u8(name: &syn::Ident, attrs: &Vec<syn::Attribute>) -> syn::Result<()> {
-	let repr_u8 = attrs
-		.iter()
-		.filter_map(|attr| {
-			if let Some(ps) = attr.path.segments.first() {
-				if ps.ident == "repr" {
-					let meta = match attr.parse_meta() {
-						Ok(meta) => meta,
-						Err(e) => return Some(Err(e)),
-					};
-					let is_repr_u8 = match meta {
-						syn::Meta::List(p) => {
-							p.nested
-								.iter()
-								.filter(|nm| match nm {
-									syn::NestedMeta::Meta(m) => match m {
-										syn::Meta::Path(p) => {
-											p.segments.iter().filter(|ps| ps.ident == "u8").count()
-												== 1
+	let mut has_repr = false;
+	for error in attrs.iter().filter_map(|attr| {
+		if let Some(ps) = attr.path.segments.first() {
+			if ps.ident == "repr" {
+				has_repr = true;
+				let meta = match attr.parse_meta() {
+					Ok(meta) => meta,
+					Err(e) => return Some(Err(e)),
+				};
+				match meta {
+					syn::Meta::List(p) => {
+						for error in p.nested.iter().filter_map(|nm| match nm {
+							syn::NestedMeta::Meta(m) => match m {
+								syn::Meta::Path(p) => {
+									for i in p.segments.iter().filter_map(|ps| {
+										if ps.ident != "u8" {
+											Some(Err(syn::Error::new(
+												ps.ident.span(),
+												"Enum is not \"repr(u8)\"",
+											)))
+										} else {
+											None
 										}
-										_ => false,
-									},
-									_ => false,
-								})
-								.count() == 1
+									}) {
+										return Some(i);
+									}
+									None
+								}
+								_ => None,
+							},
+							_ => None,
+						}) {
+							return Some(error);
 						}
-						_ => false,
-					};
-
-					if is_repr_u8 {
-						return Some(Ok(()));
-					};
-				}
+						None::<syn::Result<()>>
+					}
+					_ => None,
+				};
 			}
-			None::<syn::Result<()>>
-		})
-		.collect::<syn::Result<Vec<_>>>()?;
+		}
+		None
+	}) {
+		return error;
+	}
 
-	if repr_u8.len() != 1 {
+	if !has_repr {
 		return Err(syn::Error::new(name.span(), "Enum is not \"repr(u8)\""));
-	};
+	}
 
 	Ok(())
 }
modifiedcrates/evm-coder/tests/build_failed/abi_derive_enum_generation.stderrdiffbeforeafterboth
5 | ^^^^^^^5 | ^^^^^^^
66
7error: Enum is not "repr(u8)"7error: Enum is not "repr(u8)"
8 --> tests/build_failed/abi_derive_enum_generation.rs:12:68 --> tests/build_failed/abi_derive_enum_generation.rs:11:8
9 |9 |
1012 | enum NonReprU8 {1011 | #[repr(u32)]
11 | ^^^^^^^^^11 | ^^^
1212
13error: Enumeration parameters should not have fields13error: Enumeration parameters should not have fields
14 --> tests/build_failed/abi_derive_enum_generation.rs:21:214 --> tests/build_failed/abi_derive_enum_generation.rs:21:2