Skip to content

Commit

Permalink
feat: Error on lack of module attr for implementation of interface
Browse files Browse the repository at this point in the history
  • Loading branch information
kulikthebird committed Feb 27, 2024
1 parent 3c1bf9a commit 8994b5f
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 35 deletions.
27 changes: 20 additions & 7 deletions sylvia-derive/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub struct TraitInput<'a> {

/// Preprocessed `contract` macro input for non-trait impl block
pub struct ImplInput<'a> {
attributes: &'a ContractArgs,
attributes: Option<&'a ContractArgs>,
error: ContractErrorAttr,
item: &'a ItemImpl,
generics: Vec<&'a GenericParam>,
Expand Down Expand Up @@ -144,7 +144,7 @@ impl<'a> TraitInput<'a> {
}

impl<'a> ImplInput<'a> {
pub fn new(attributes: &'a ContractArgs, item: &'a ItemImpl) -> Self {
pub fn new(item: &'a ItemImpl) -> Self {
let generics = item.generics.params.iter().collect();
let parsed_attrs = ParsedSylviaAttributes::new(item.attrs.iter());
let error = parsed_attrs.error_attrs.unwrap_or_default();
Expand All @@ -153,7 +153,7 @@ impl<'a> ImplInput<'a> {
let interfaces = Interfaces::new(item);

Self {
attributes,
attributes: None,
item,
generics,
error,
Expand All @@ -163,6 +163,13 @@ impl<'a> ImplInput<'a> {
}
}

pub fn new_with_module(attributes: &'a ContractArgs, item: &'a ItemImpl) -> Self {
Self {
attributes: Some(attributes),
..Self::new(item)
}
}

pub fn process(&self) -> TokenStream {
match is_trait(self.item) {
true => self.process_interface(),
Expand Down Expand Up @@ -273,7 +280,7 @@ impl<'a> ImplInput<'a> {
}

fn emit_querier_for_bound_impl(&self) -> TokenStream {
let contract_module = self.attributes.module.as_ref();
let contract_module = self.attributes.map(|contract_args| &contract_args.module);
let variants_args =
MsgVariants::<GenericParam>::new(self.item.as_variants(), MsgType::Query, &[], &None);
let associated_types = ImplAssociatedTypes::new(self.item);
Expand All @@ -299,11 +306,17 @@ impl<'a> ImplInput<'a> {
interfaces,
..
} = self;
let contract_module = self.attributes.module.as_ref();
let generic_params = &self.generics;

if is_trait(item) {
ImplMtHelpers::new(item, generic_params, custom, interfaces, &contract_module).emit()
if let Some(contract_module) = self.attributes {
ImplMtHelpers::new(
item,
generic_params,
custom,
interfaces,
&contract_module.module,
)
.emit()
} else {
ContractMtHelpers::new(item, generic_params, custom, override_entry_points.clone())
.emit()
Expand Down
9 changes: 6 additions & 3 deletions sylvia-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,13 @@ pub fn contract(attr: TokenStream, item: TokenStream) -> TokenStream {

fn contract_impl(attr: TokenStream2, item: TokenStream2) -> TokenStream2 {
fn inner(attr: TokenStream2, item: TokenStream2) -> syn::Result<TokenStream2> {
let attrs: parser::ContractArgs = parse2(attr)?;
let input: ItemImpl = parse2(item)?;

let expanded = ImplInput::new(&attrs, &input).process();
let expanded = if input.trait_.is_some() {
let attrs: parser::ContractArgs = parse2(attr)?;
ImplInput::new_with_module(&attrs, &input).process()
} else {
ImplInput::new(&input).process()
};
let input = StripInput.fold_item_impl(input);

Ok(quote! {
Expand Down
9 changes: 3 additions & 6 deletions sylvia-derive/src/multitest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ pub struct ImplMtHelpers<'a> {
exec_variants: MsgVariants<'a, GenericParam>,
query_variants: MsgVariants<'a, GenericParam>,
where_clause: &'a Option<syn::WhereClause>,
contract_module: &'a Option<&'a Path>,
contract_module: &'a Path,
contract_name: &'a Ident,
}

Expand All @@ -641,7 +641,7 @@ impl<'a> ImplMtHelpers<'a> {
generic_params: &'a [&'a GenericParam],
custom: &'a Custom,
interfaces: &'a Interfaces,
contract_module: &'a Option<&'a Path>,
contract_module: &'a Path,
) -> Self {
let where_clause = &source.generics.where_clause;
let exec_variants = MsgVariants::new(
Expand Down Expand Up @@ -766,10 +766,7 @@ impl<'a> ImplMtHelpers<'a> {
&associated_items,
);

let contract_module = match contract_module {
Some(contract_module) => quote! { #contract_module :: },
None => quote! {},
};
let contract_module = quote! { #contract_module :: };
let contract_proxy = Ident::new(&format!("{}Proxy", contract_name), contract_name.span());

let where_predicates = where_clause
Expand Down
35 changes: 16 additions & 19 deletions sylvia-derive/src/parser/contract.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,35 @@
use proc_macro_error::abort;
use syn::{
parse::{Error, Nothing, Parse, ParseStream},
Ident, Path, Result, Token,
parse::{Nothing, Parse, ParseStream},
Error, Ident, Path, Result, Token,
};

/// Parsed arguments for `contract` macro
pub struct ContractArgs {
/// Module in which contract impl block is defined.
/// Used only while implementing `Interface` on `Contract`.
pub module: Option<Path>,
pub module: Path,
}

impl Parse for ContractArgs {
fn parse(input: ParseStream) -> Result<Self> {
let mut module = None;

while !input.is_empty() {
let attr: Ident = input.parse()?;
let maybe_module = input.parse().and_then(|attr: Ident| -> Result<Path> {
let _: Token![=] = input.parse()?;

if attr == "module" {
module = Some(input.parse()?);
input.parse()
} else {
return Err(Error::new(attr.span(), "expected `module`"));
}

if input.peek(Token![,]) {
let _: Token![,] = input.parse()?;
} else if !input.is_empty() {
return Err(input.error("Unexpected token, comma expected"));
Err(Error::new(attr.span(), "Missing `module` attribute"))

Check warning on line 21 in sylvia-derive/src/parser/contract.rs

View check run for this annotation

Codecov / codecov/patch

sylvia-derive/src/parser/contract.rs#L21

Added line #L21 was not covered by tests
}
}

});
let module: Path = match maybe_module {
Ok(module) => module,
Err(e) => abort!(
e.span(), "The module path needs to be provided `#[contract(module=path::to::contract)`.";
note = "Implementing interface on a contract requires to point the path to the contract structure.";
note = "Parsing error: {}", e

Check warning on line 29 in sylvia-derive/src/parser/contract.rs

View check run for this annotation

Codecov / codecov/patch

sylvia-derive/src/parser/contract.rs#L26-L29

Added lines #L26 - L29 were not covered by tests
),
};
let _: Nothing = input.parse()?;

Ok(ContractArgs { module })
}
}

0 comments on commit 8994b5f

Please sign in to comment.