Skip to content
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

Conditional compilation #1707

Merged
merged 28 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Basic support for `dyn Trait` to allow cross-contract calls only with trait - [#1673](https://github.com/paritytech/ink/pull/1673)
- E2E: auto detect contracts to be built - [#1691](https://github.com/paritytech/ink/pull/1691)
- Add `set_code_hash` to `EnvAccess` - [#1698](https://github.com/paritytech/ink/pull/1698)
- Support conditional compilation - [#1707](https://github.com/paritytech/ink/pull/1707)
SkymanOne marked this conversation as resolved.
Show resolved Hide resolved

## Version 4.0.1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ impl CallBuilder<'_> {
let span = message.span();
let message_ident = message.ident();
let output_ident = generator::output_ident(message_ident);
let cfg_attrs = message.get_cfg_attrs(span);
let trait_info_id = generator::generate_reference_to_trait_info(span, trait_path);
let (input_bindings, input_types): (Vec<_>, Vec<_>) = message
.callable()
Expand All @@ -295,13 +296,15 @@ impl CallBuilder<'_> {
.whitelisted_attributes()
.filter_attr(message.attrs().to_vec());
quote_spanned!(span=>
#( #cfg_attrs )*
type #output_ident = <<<
Self
as ::ink::codegen::TraitCallForwarderFor<{#trait_info_id}>>::Forwarder
as ::ink::codegen::TraitCallBuilder>::Builder
as #trait_path>::#output_ident;

#[inline]
#( #cfg_attrs )*
SkymanOne marked this conversation as resolved.
Show resolved Hide resolved
#( #attrs )*
fn #message_ident(
& #mut_token self
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,14 @@ impl ContractRef<'_> {
let mut_token = message.receiver().is_ref_mut().then(|| quote! { mut });
let input_bindings = message.inputs().map(|input| &input.pat).collect::<Vec<_>>();
let input_types = message.inputs().map(|input| &input.ty).collect::<Vec<_>>();
let cfg_attrs = message.get_cfg_attrs(span);
quote_spanned!(span=>
#( #cfg_attrs )*
type #output_ident =
<<Self::__ink_TraitInfo as ::ink::codegen::TraitCallForwarder>::Forwarder as #trait_path>::#output_ident;

#[inline]
#( #cfg_attrs )*
fn #message_ident(
& #mut_token self
#( , #input_bindings : #input_types )*
Expand Down
602 changes: 315 additions & 287 deletions crates/ink/codegen/src/generator/dispatch.rs

Large diffs are not rendered by default.

21 changes: 19 additions & 2 deletions crates/ink/codegen/src/generator/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,23 @@ impl<'a> Events<'a> {
.events()
.map(|event| event.ident())
.collect::<Vec<_>>();
let event_idents_cfgs = self
.contract
.module()
.events()
.map(|event| event.get_cfg_attrs(event.span()))
.collect::<Vec<_>>();
let base_event_ident =
proc_macro2::Ident::new("__ink_EventBase", Span::call_site());
quote! {
#[allow(non_camel_case_types)]
#[derive(::scale::Encode, ::scale::Decode)]
#[cfg(not(feature = "__ink_dylint_EventBase"))]
pub enum #base_event_ident {
#( #event_idents(#event_idents), )*
#(
#( #event_idents_cfgs )*
#event_idents(#event_idents),
)*
}

const _: () = {
Expand All @@ -107,6 +116,7 @@ impl<'a> Events<'a> {
};

#(
#( #event_idents_cfgs )*
const _: () = {
impl From<#event_idents> for #base_event_ident {
fn from(event: #event_idents) -> Self {
Expand Down Expand Up @@ -135,10 +145,12 @@ impl<'a> Events<'a> {
{
match self {
#(
#( #event_idents_cfgs )*
Self::#event_idents(event) => {
<#event_idents as ::ink::env::Topics>::topics::<E, B>(event, builder)
}
)*
)*,
_ => panic!("Event does not exist!")
}
}
}
Expand All @@ -151,16 +163,19 @@ impl<'a> Events<'a> {
let span = event.span();
let storage_ident = self.contract.module().storage().ident();
let event_ident = event.ident();
let cfg_attrs = event.get_cfg_attrs(span);
let len_topics = event.fields().filter(|event| event.is_topic).count();
let max_len_topics = quote_spanned!(span=>
<<#storage_ident as ::ink::env::ContractEnv>::Env
as ::ink::env::Environment>::MAX_EVENT_TOPICS
);
quote_spanned!(span=>
#( #cfg_attrs )*
impl ::ink::codegen::EventLenTopics for #event_ident {
type LenTopics = ::ink::codegen::EventTopics<#len_topics>;
}

#( #cfg_attrs )*
const _: () = ::ink::codegen::utils::consume_type::<
::ink::codegen::EventRespectsTopicLimit<
#event_ident,
Expand Down Expand Up @@ -227,7 +242,9 @@ impl<'a> Events<'a> {
0 => quote_spanned!(span=> ::ink::env::topics::state::NoRemainingTopics),
n => quote_spanned!(span=> [::ink::env::topics::state::HasRemainingTopics; #n]),
};
let cfg_attrs = event.get_cfg_attrs(span);
quote_spanned!(span =>
#( #cfg_attrs )*
const _: () = {
impl ::ink::env::Topics for #event_ident {
type RemainingTopics = #remaining_topics_ty;
Expand Down
1 change: 1 addition & 0 deletions crates/ink/codegen/src/generator/item_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ impl ItemImpls<'_> {
.unwrap_or_else(|| syn::parse_quote! { () });
let statements = message.statements();
quote_spanned!(span =>
#( #attrs )*
SkymanOne marked this conversation as resolved.
Show resolved Hide resolved
type #output_ident = #output;

#( #attrs )*
Expand Down
8 changes: 8 additions & 0 deletions crates/ink/codegen/src/generator/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,9 @@ impl Metadata<'_> {
let args = constructor.inputs().map(Self::generate_dispatch_argument);
let storage_ident = self.contract.module().storage().ident();
let ret_ty = Self::generate_constructor_return_type(storage_ident, selector_id);
let cfg_attrs = constructor.get_cfg_attrs(span);
quote_spanned!(span=>
#( #cfg_attrs )*
::ink::metadata::ConstructorSpec::from_label(::core::stringify!(#ident))
.selector([
#( #selector_bytes ),*
Expand Down Expand Up @@ -237,8 +239,10 @@ impl Metadata<'_> {
let mutates = message.receiver().is_ref_mut();
let ident = message.ident();
let args = message.inputs().map(Self::generate_dispatch_argument);
let cfg_attrs = message.get_cfg_attrs(span);
let ret_ty = Self::generate_return_type(Some(&message.wrapped_output()));
quote_spanned!(span =>
#( #cfg_attrs )*
::ink::metadata::MessageSpec::from_label(::core::stringify!(#ident))
.selector([
#( #selector_bytes ),*
Expand Down Expand Up @@ -285,6 +289,7 @@ impl Metadata<'_> {
let message_args = message
.inputs()
.map(Self::generate_dispatch_argument);
let cfg_attrs = message.get_cfg_attrs(message_span);
let mutates = message.receiver().is_ref_mut();
let local_id = message.local_id().hex_padded_suffixed();
let is_payable = quote! {{
Expand All @@ -300,6 +305,7 @@ impl Metadata<'_> {
let ret_ty = Self::generate_return_type(Some(&message.wrapped_output()));
let label = [trait_ident.to_string(), message_ident.to_string()].join("::");
quote_spanned!(message_span=>
#( #cfg_attrs )*
::ink::metadata::MessageSpec::from_label(#label)
.selector(#selector)
.args([
Expand Down Expand Up @@ -364,7 +370,9 @@ impl Metadata<'_> {
let ident = event.ident();
let docs = event.attrs().iter().filter_map(|attr| attr.extract_docs());
let args = Self::generate_event_args(event);
let cfg_attrs = event.get_cfg_attrs(span);
quote_spanned!(span =>
#( #cfg_attrs )*
::ink::metadata::EventSpec::new(::core::stringify!(#ident))
.args([
#( #args ),*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ impl CallBuilder<'_> {
let mut_tok = message.mutates().then(|| quote! { mut });
quote_spanned!(span =>
#[allow(clippy::type_complexity)]
#( #attrs )*
SkymanOne marked this conversation as resolved.
Show resolved Hide resolved
type #output_ident = ::ink::env::call::CallBuilder<
Self::Env,
::ink::env::call::utils::Set< ::ink::env::call::Call< Self::Env > >,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ impl CallForwarder<'_> {
"encountered error while calling <{forwarder_ident} as {trait_ident}>::{message_ident}",
);
quote_spanned!(span =>
#( #attrs )*
SkymanOne marked this conversation as resolved.
Show resolved Hide resolved
type #output_ident = #output_type;

#( #attrs )*
Expand Down
1 change: 1 addition & 0 deletions crates/ink/codegen/src/generator/trait_def/definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ impl<'a> TraitDefinition<'a> {
format_ident!("{}Output", ident.to_string().to_lower_camel_case());
quote_spanned!(span =>
/// Output type of the respective trait message.
#(#attrs)*
SkymanOne marked this conversation as resolved.
Show resolved Hide resolved
type #output_ident: ::ink::codegen::ImpliesReturn<#output>;

#(#attrs)*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ impl TraitRegistry<'_> {
}
};
quote_spanned!(span=>
#( #attrs )*
SkymanOne marked this conversation as resolved.
Show resolved Hide resolved
type #output_ident = #output_type;

#( #attrs )*
Expand Down
44 changes: 43 additions & 1 deletion crates/ink/ir/src/ir/item/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ use crate::{
use proc_macro2::{
Ident,
Span,
TokenStream,
};
use quote::quote_spanned;
use syn::spanned::Spanned as _;

/// An ink! event struct definition.
Expand Down Expand Up @@ -100,6 +102,14 @@ impl TryFrom<syn::ItemStruct> for Event {
utils::ensure_pub_visibility("event structs", struct_span, &item_struct.vis)?;
'repeat: for field in item_struct.fields.iter() {
let field_span = field.span();
let some_cfg_attrs =
field.attrs.iter().find(|attr| attr.path.is_ident("cfg"));
if some_cfg_attrs.is_some() {
return Err(format_err!(
field_span,
"conditional compilation is not allowed for event field"
))
}
let (ink_attrs, _) = ir::partition_attributes(field.attrs.clone())?;
if ink_attrs.is_empty() {
continue 'repeat
Expand All @@ -112,7 +122,7 @@ impl TryFrom<syn::ItemStruct> for Event {
return Err(format_err!(
field_span,
"first optional ink! attribute of an event field must be #[ink(topic)]",
))
));
}
for arg in normalized.args() {
if !matches!(arg.kind(), ir::AttributeArg::Topic) {
Expand Down Expand Up @@ -149,6 +159,22 @@ impl Event {
pub fn attrs(&self) -> &[syn::Attribute] {
&self.item.attrs
}

/// Returns a list of `cfg` attributes if any.
pub fn get_cfg_attrs(&self, span: Span) -> Vec<TokenStream> {
self.item
.attrs
.iter()
.filter(|a| a.path.is_ident("cfg"))
SkymanOne marked this conversation as resolved.
Show resolved Hide resolved
.map(|a| {
a.tokens
.clone()
.into_iter()
.map(|token| quote_spanned!(span=> #[cfg #token]))
.collect()
})
.collect()
}
}

/// An event field with a flag indicating if this field is an event topic.
Expand Down Expand Up @@ -385,6 +411,22 @@ mod tests {
)
}

#[test]
fn cfg_marked_field_attribute_fails() {
assert_try_from_fails(
syn::parse_quote! {
#[ink(event)]
pub struct MyEvent {
#[ink(topic)]
field_1: i32,
#[cfg(unix)]
field_2: bool,
}
},
"conditional compilation is not allowed for event field",
)
}

/// Used for the event fields iterator unit test because `syn::Field` does
/// not provide a `syn::parse::Parse` implementation.
#[derive(Debug, PartialEq, Eq)]
Expand Down
18 changes: 18 additions & 0 deletions crates/ink/ir/src/ir/item_impl/constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ use crate::{
use proc_macro2::{
Ident,
Span,
TokenStream,
};
use quote::quote_spanned;
use syn::spanned::Spanned as _;

/// An ink! constructor definition.
Expand Down Expand Up @@ -220,6 +222,22 @@ impl Constructor {
&self.item.attrs
}

/// Returns a list of `cfg` attributes if any.
pub fn get_cfg_attrs(&self, span: Span) -> Vec<TokenStream> {
self.item
SkymanOne marked this conversation as resolved.
Show resolved Hide resolved
.attrs
.iter()
.filter(|a| a.path.is_ident("cfg"))
.map(|a| {
a.tokens
.clone()
.into_iter()
.map(|token| quote_spanned!(span=> #[cfg #token]))
.collect()
})
.collect()
}

/// Returns the return type of the ink! constructor if any.
pub fn output(&self) -> Option<&syn::Type> {
match &self.item.sig.output {
Expand Down
18 changes: 18 additions & 0 deletions crates/ink/ir/src/ir/item_impl/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ use crate::ir::{
use proc_macro2::{
Ident,
Span,
TokenStream,
};
use quote::quote_spanned;
use syn::spanned::Spanned as _;

/// The receiver of an ink! message.
Expand Down Expand Up @@ -268,6 +270,22 @@ impl Message {
&self.item.attrs
}

/// Returns a list of `cfg` attributes if any.
pub fn get_cfg_attrs(&self, span: Span) -> Vec<TokenStream> {
self.item
.attrs
.iter()
.filter(|a| a.path.is_ident("cfg"))
.map(|a| {
a.tokens
.clone()
.into_iter()
.map(|token| quote_spanned!(span=> #[cfg #token]))
.collect()
})
.collect()
}

/// Returns the `self` receiver of the ink! message.
pub fn receiver(&self) -> Receiver {
match self.item.sig.inputs.iter().next() {
Expand Down
Loading