Unverified Commit b4e2781c authored by Robin Freyler's avatar Robin Freyler Committed by GitHub
Browse files

Misc cleanups in ink! codegen (#935)

* remove some duplicated AsRef impl code in generators

* improve #[ink::test] macro hygiene and error message upon failure

* import standard ink! traits anonymously in codegen

* modernize and improve macro hygiene of metadata codegen

* modernize and simplify and improve macro hygiene of storage codegen

* extend selector_works unit test

* fix minor error in item impl error message
parent 87867ef8
Pipeline #158509 passed with stages
in 28 minutes and 47 seconds
......@@ -27,12 +27,7 @@ pub struct Contract<'a> {
/// The contract to generate code for.
contract: &'a ir::Contract,
}
impl AsRef<ir::Contract> for Contract<'_> {
fn as_ref(&self) -> &ir::Contract {
self.contract
}
}
impl_as_ref_for_generator!(Contract);
impl GenerateCode for Contract<'_> {
/// Generates ink! contract code.
......
......@@ -50,12 +50,7 @@ use syn::spanned::Spanned as _;
pub struct Dispatch<'a> {
contract: &'a ir::Contract,
}
impl AsRef<ir::Contract> for Dispatch<'_> {
fn as_ref(&self) -> &ir::Contract {
self.contract
}
}
impl_as_ref_for_generator!(Dispatch);
impl GenerateCode for Dispatch<'_> {
fn generate_code(&self) -> TokenStream2 {
......
......@@ -33,12 +33,7 @@ use syn::spanned::Spanned as _;
pub struct Events<'a> {
contract: &'a ir::Contract,
}
impl AsRef<ir::Contract> for Events<'_> {
fn as_ref(&self) -> &ir::Contract {
self.contract
}
}
impl_as_ref_for_generator!(Events);
impl GenerateCode for Events<'_> {
fn generate_code(&self) -> TokenStream2 {
......
......@@ -50,10 +50,10 @@ impl GenerateCode for InkTest<'_> {
let _: () = {
#fn_block
};
Ok(())
::core::result::Result::Ok(())
}
})
.expect(#expect_msg);
.unwrap_or_else(|error| ::core::panic!("{}: {:?}", #expect_msg, error));
}
}
}
......
......@@ -34,12 +34,7 @@ use syn::spanned::Spanned as _;
pub struct ItemImpls<'a> {
contract: &'a ir::Contract,
}
impl AsRef<ir::Contract> for ItemImpls<'_> {
fn as_ref(&self) -> &ir::Contract {
self.contract
}
}
impl_as_ref_for_generator!(ItemImpls);
impl GenerateCode for ItemImpls<'_> {
fn generate_code(&self) -> TokenStream2 {
......@@ -53,7 +48,7 @@ impl GenerateCode for ItemImpls<'_> {
quote! {
#no_cross_calling_cfg
const _: () = {
use ::ink_lang::{Env, EmitEvent, StaticEnv};
use ::ink_lang::{Env as _, EmitEvent as _, StaticEnv as _};
#( #item_impls )*
};
......
......@@ -69,7 +69,7 @@ impl Metadata<'_> {
quote! {
<#contract_ident as ::ink_storage::traits::StorageLayout>::layout(
&mut <::ink_primitives::KeyPtr as ::core::convert::From<::ink_primitives::Key>>::from(
<::ink_primitives::Key as ::core::convert::From<[::core::primitive::u8; 32]>>::from([0x00_u8; 32])
<::ink_primitives::Key as ::core::convert::From<[::core::primitive::u8; 32usize]>>::from([0x00_u8; 32usize])
)
)
}
......@@ -84,16 +84,16 @@ impl Metadata<'_> {
quote! {
::ink_metadata::ContractSpec::new()
.constructors([
#(#constructors ,)*
#( #constructors ),*
])
.messages([
#(#messages ,)*
#( #messages ),*
])
.events([
#(#events ,)*
#( #events ),*
])
.docs([
#(#docs ,)*
#( #docs ),*
])
.done()
}
......@@ -141,27 +141,30 @@ impl Metadata<'_> {
let selector_bytes = constructor.composed_selector().hex_lits();
let constructor = constructor.callable();
let ident = constructor.ident();
let ident_lit = ident.to_string();
let args = constructor
.inputs()
.map(|arg| Self::generate_message_param(arg));
let constr = match trait_ident {
Some(trait_ident) => {
let trait_ident_lit = trait_ident.to_string();
quote_spanned!(span => from_trait_and_name(#trait_ident_lit, #ident_lit))
quote_spanned!(span => from_trait_and_name(
::core::stringify!(#trait_ident),
::core::stringify!(#ident)
))
}
None => {
quote_spanned!(span => from_name(#ident_lit))
quote_spanned!(span => from_name(::core::stringify!(#ident)))
}
};
quote_spanned!(span =>
::ink_metadata::ConstructorSpec::#constr
.selector([#(#selector_bytes),*])
.selector([
#( #selector_bytes ),*
])
.args([
#(#args ,)*
#( #args ),*
])
.docs([
#(#docs ,)*
#( #docs ),*
])
.done()
)
......@@ -174,10 +177,9 @@ impl Metadata<'_> {
syn::Pat::Ident(ident) => &ident.ident,
_ => unreachable!("encountered unexpected non identifier in ink! parameter"),
};
let ident_lit = ident.to_string();
let type_spec = Self::generate_type_spec(&pat_type.ty);
quote! {
::ink_metadata::MessageParamSpec::new(#ident_lit)
::ink_metadata::MessageParamSpec::new(::core::stringify!(#ident))
.of_type(#type_spec)
.done()
}
......@@ -203,7 +205,7 @@ impl Metadata<'_> {
.collect::<Vec<_>>();
quote! {
::ink_metadata::TypeSpec::with_name_segs::<#ty, _>(
::core::iter::IntoIterator::into_iter([#(#segs),*])
::core::iter::IntoIterator::into_iter([ #( #segs ),* ])
.map(::core::convert::AsRef::as_ref)
)
}
......@@ -234,31 +236,34 @@ impl Metadata<'_> {
let message = message.callable();
let mutates = message.receiver().is_ref_mut();
let ident = message.ident();
let ident_lit = ident.to_string();
let args = message
.inputs()
.map(|arg| Self::generate_message_param(arg));
let ret_ty = Self::generate_return_type(message.output());
let constr = match trait_ident {
Some(trait_ident) => {
let trait_ident_lit = trait_ident.to_string();
quote_spanned!(span => from_trait_and_name(#trait_ident_lit, #ident_lit))
quote_spanned!(span => from_trait_and_name(
::core::stringify!(#trait_ident),
::core::stringify!(#ident),
))
}
None => {
quote_spanned!(span => from_name(#ident_lit))
quote_spanned!(span => from_name(::core::stringify!(#ident)))
}
};
quote_spanned!(span =>
::ink_metadata::MessageSpec::#constr
.selector([#(#selector_bytes),*])
.selector([
#( #selector_bytes ),*
])
.args([
#(#args ,)*
#( #args ),*
])
.returns(#ret_ty)
.mutates(#mutates)
.payable(#is_payable)
.docs([
#(#docs ,)*
#( #docs ),*
])
.done()
)
......@@ -270,7 +275,7 @@ impl Metadata<'_> {
match ret_ty {
None => {
quote! {
::ink_metadata::ReturnTypeSpec::new(None)
::ink_metadata::ReturnTypeSpec::new(::core::option::Option::None)
}
}
Some(ty) => {
......@@ -287,16 +292,15 @@ impl Metadata<'_> {
self.contract.module().events().map(|event| {
let span = event.span();
let ident = event.ident();
let ident_lit = ident.to_string();
let docs = Self::extract_doc_comments(event.attrs());
let args = Self::generate_event_args(event);
quote_spanned!(span =>
::ink_metadata::EventSpec::new(#ident_lit)
::ink_metadata::EventSpec::new(::core::stringify!(#ident))
.args([
#( #args, )*
#( #args ),*
])
.docs([
#( #docs, )*
#( #docs ),*
])
.done()
)
......@@ -308,17 +312,16 @@ impl Metadata<'_> {
event.fields().map(|event_field| {
let span = event_field.span();
let ident = event_field.ident();
let ident_lit = ident.map(ToString::to_string);
let is_topic = event_field.is_topic;
let attrs = event_field.attrs();
let docs = Self::extract_doc_comments(&attrs);
let ty = Self::generate_type_spec(event_field.ty());
quote_spanned!(span =>
::ink_metadata::EventParamSpec::new(#ident_lit)
::ink_metadata::EventParamSpec::new(::core::stringify!(#ident))
.of_type(#ty)
.indexed(#is_topic)
.docs([
#( #docs, )*
#( #docs ),*
])
.done()
)
......
......@@ -12,6 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
/// Implements `AsRef` for a code generator type.
///
/// Code generators always have a shared `contract` reference to the contract.
/// They need to implement this trait in order to use other code generators.
macro_rules! impl_as_ref_for_generator {
( $generator_name:ident ) => {
impl ::core::convert::AsRef<ir::Contract> for $generator_name<'_> {
fn as_ref(&self) -> &ir::Contract {
self.contract
}
}
};
}
mod chain_extension;
mod contract;
mod cross_calling;
......
......@@ -30,24 +30,18 @@ use syn::spanned::Spanned as _;
pub struct Storage<'a> {
contract: &'a ir::Contract,
}
impl<'a> AsRef<ir::Contract> for Storage<'_> {
fn as_ref(&self) -> &ir::Contract {
self.contract
}
}
impl_as_ref_for_generator!(Storage);
impl GenerateCode for Storage<'_> {
fn generate_code(&self) -> TokenStream2 {
let storage_span = self.contract.module().storage().span();
let access_env_impls = self.generate_access_env_trait_impls();
let storage_struct = self.generate_storage_struct();
let use_emit_event = if self.contract.module().events().next().is_some() {
// Required to allow for `self.env().emit_event(..)` in messages and constructors.
Some(quote! { use ::ink_lang::EmitEvent as _; })
} else {
None
};
let use_emit_event =
self.contract.module().events().next().is_some().then(|| {
// Required to allow for `self.env().emit_event(..)` in messages and constructors.
quote! { use ::ink_lang::EmitEvent as _; }
});
let cfg = self.generate_code_using::<generator::CrossCallingConflictCfg>();
quote_spanned!(storage_span =>
#access_env_impls
......@@ -75,18 +69,22 @@ impl Storage<'_> {
#cfg
const _: () = {
impl<'a> ::ink_lang::Env for &'a #storage_ident {
type EnvAccess = ::ink_lang::EnvAccess<'a, <#storage_ident as ::ink_lang::ContractEnv>::Env>;
type EnvAccess = ::ink_lang::EnvAccess<
'a, <#storage_ident as ::ink_lang::ContractEnv>::Env>;
fn env(self) -> Self::EnvAccess {
Default::default()
<<Self as ::ink_lang::Env>::EnvAccess
as ::core::default::Default>::default()
}
}
impl<'a> ::ink_lang::StaticEnv for #storage_ident {
type EnvAccess = ::ink_lang::EnvAccess<'static, <#storage_ident as ::ink_lang::ContractEnv>::Env>;
type EnvAccess = ::ink_lang::EnvAccess<
'static, <#storage_ident as ::ink_lang::ContractEnv>::Env>;
fn env() -> Self::EnvAccess {
Default::default()
<<Self as ::ink_lang::StaticEnv>::EnvAccess
as ::core::default::Default>::default()
}
}
};
......@@ -97,8 +95,8 @@ impl Storage<'_> {
fn generate_storage_struct(&self) -> TokenStream2 {
let storage = self.contract.module().storage();
let span = storage.span();
let ident = &storage.ident();
let attrs = &storage.attrs();
let ident = storage.ident();
let attrs = storage.attrs();
let fields = storage.fields();
let cfg = self.generate_code_using::<generator::CrossCallingConflictCfg>();
quote_spanned!( span =>
......@@ -109,7 +107,7 @@ impl Storage<'_> {
derive(::ink_storage::traits::StorageLayout)
)]
#[derive(::ink_storage::traits::SpreadLayout)]
#[cfg_attr(test, derive(Debug))]
#[cfg_attr(test, derive(::core::fmt::Debug))]
pub struct #ident {
#( #fields ),*
}
......
......@@ -1037,6 +1037,14 @@ mod tests {
#[test]
fn selector_works() {
assert_attribute_try_from(
syn::parse_quote! {
#[ink(selector = 42)]
},
Ok(test::Attribute::Ink(vec![AttributeArg::Selector(
Selector::from_bytes([0, 0, 0, 42]),
)])),
);
assert_attribute_try_from(
syn::parse_quote! {
#[ink(selector = 0xDEADBEEF)]
......
......@@ -218,7 +218,7 @@ impl TryFrom<syn::ItemImpl> for ItemImpl {
if !Self::is_ink_impl_block(&item_impl)? {
return Err(format_err_spanned!(
item_impl,
"missing ink! annotations on 16 kB block or on any of its items"
"missing ink! annotations on implementation block or on any of its items"
))
}
if let Some(defaultness) = item_impl.defaultness {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment