Repository: CosmWasm/sylvia
Pull request #408 (2024-07-30 14:45:17)

feat: Emit error if contract macro is above entry_points

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/CosmWasm/sylvia/pull/408?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) Report
Attention: Patch coverage is `0%` with `19 lines` in your changes missing coverage. Please review.
> Project coverage is 85.01%. Comparing base [(`8f6d1f6`)](https://app.codecov.io/gh/CosmWasm/sylvia/commit/8f6d1f62ca8a50d93f3a03895ac652b85ce03b67?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) to head [(`9e5e62f`)](https://app.codecov.io/gh/CosmWasm/sylvia/commit/9e5e62f3be6133fd2eb38a0b2461734c4249e9b7?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm).

| [Files](https://app.codecov.io/gh/CosmWasm/sylvia/pull/408?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) | Patch % | Lines |
|---|---|---|
| [sylvia-derive/src/input.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/408?src=pr&el=tree&filepath=sylvia-derive%2Fsrc%2Finput.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvaW5wdXQucnM=) | 0.00% | [15 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/408?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |
| [sylvia-derive/src/lib.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/408?src=pr&el=tree&filepath=sylvia-derive%2Fsrc%2Flib.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvbGliLnJz) | 0.00% | [2 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/408?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |
| [sylvia-derive/src/message.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/408?src=pr&el=tree&filepath=sylvia-derive%2Fsrc%2Fmessage.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvbWVzc2FnZS5ycw==) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/408?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |
| [sylvia-derive/src/parser/entry\_point.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/408?src=pr&el=tree&filepath=sylvia-derive%2Fsrc%2Fparser%2Fentry_point.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvcGFyc2VyL2VudHJ5X3BvaW50LnJz) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/408?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |

<details><summary>Additional details and impacted files</summary>


```diff
@@                       Coverage Diff                        @@
##           jawoznia/entry_points_errors     #408      +/-   ##
================================================================
- Coverage                         85.33%   85.01%   -0.33%     
================================================================
  Files                                42       42              
  Lines                              2905     2916      +11     
================================================================
  Hits                               2479     2479              
- Misses                              426      437      +11     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/CosmWasm/sylvia/pull/408?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm).


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 91c9c18..2c30508 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -101,6 +101,45 @@ jobs:
           path: |
             examples/contracts/**/schema/*.json
 
+  # Errors differ between Rust versions. We test only the latest output.
+  test_ui:
+    name: Test UI
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - build: macOS
+            os: macOS-latest
+          - build: Windows
+            os: windows-latest
+    defaults:
+      run:
+        shell: bash
+        working-directory: ./
+    steps:
+      - name: Checkout sources
+        uses: actions/checkout@v2
+      - name: Cache
+        uses: actions/cache@v3
+        with:
+          path: |
+            ~/.cargo/bin/
+            ~/.cargo/registry/index/
+            ~/.cargo/registry/cache/
+            ~/.cargo/git/db/
+            target/
+          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+      - name: Install Rust
+        uses: actions-rs/toolchain@v1
+        with:
+          toolchain: stable
+          target: wasm32-unknown-unknown
+          profile: minimal
+          override: true
+      - name: Test project
+        run: cargo test --locked -- --ignored
+
   coverage:
     name: Code coverage
     runs-on: ubuntu-latest
diff --git a/Cargo.lock b/Cargo.lock
index b3ebf94..924cde8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -186,11 +186,17 @@ version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790"
 
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
 [[package]]
 name = "bytes"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
+checksum = "fca2be1d5c43812bae364ee3f30b3afcb7877cf59f4aeb94c66f313a41d2fac9"
 
 [[package]]
 name = "cfg-if"
@@ -797,9 +803,13 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
 
 [[package]]
 name = "ppv-lite86"
-version = "0.2.17"
+version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+checksum = "2288c0e17cc8d342c712bb43a257a80ebffce59cdb33d5000d8348f3ec02528b"
+dependencies = [
+ "zerocopy",
+ "zerocopy-derive",
+]
 
 [[package]]
 name = "primeorder"
@@ -1052,20 +1062,21 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.120"
+version = "1.0.121"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
+checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609"
 dependencies = [
  "itoa",
+ "memchr",
  "ryu",
  "serde",
 ]
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.6"
+version = "0.6.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
+checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
 dependencies = [
  "serde",
 ]
@@ -1210,21 +1221,21 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.8.14"
+version = "0.8.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
+checksum = "7a44eede9b727419af8095cb2d72fab15487a541f54647ad4414b34096ee4631"
 dependencies = [
  "serde",
  "serde_spanned",
  "toml_datetime",
- "toml_edit 0.22.15",
+ "toml_edit 0.22.18",
 ]
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.6"
+version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
 dependencies = [
  "serde",
 ]
@@ -1242,22 +1253,22 @@ dependencies = [
 
 [[package]]
 name = "toml_edit"
-version = "0.22.15"
+version = "0.22.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d59a3a72298453f564e2b111fa896f8d07fabb36f51f06d7e875fc5e0b5a3ef1"
+checksum = "1490595c74d930da779e944f5ba2ecdf538af67df1a9848cbd156af43c1b7cf0"
 dependencies = [
  "indexmap",
  "serde",
  "serde_spanned",
  "toml_datetime",
- "winnow 0.6.13",
+ "winnow 0.6.16",
 ]
 
 [[package]]
 name = "trybuild"
-version = "1.0.97"
+version = "1.0.98"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b1e5645f2ee8025c2f1d75e1138f2dd034d74e6ba54620f3c569ba2a2a1ea06"
+checksum = "b55265878356bdd85c9baa15859c87de93b2bf1f33acf752040a561e4a228f62"
 dependencies = [
  "glob",
  "serde",
@@ -1308,9 +1319,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
 
 [[package]]
 name = "version_check"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
 
 [[package]]
 name = "wasi"
@@ -1411,9 +1422,9 @@ dependencies = [
 
 [[package]]
 name = "winnow"
-version = "0.6.13"
+version = "0.6.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1"
+checksum = "b480ae9340fc261e6be3e95a1ba86d54ae3f9171132a73ce8d4bbaf68339507c"
 dependencies = [
  "memchr",
 ]
@@ -1424,6 +1435,7 @@ version = "0.7.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
 dependencies = [
+ "byteorder",
  "zerocopy-derive",
 ]
 
diff --git a/sylvia-derive/src/input.rs b/sylvia-derive/src/input.rs
index 148ae7c..582df26 100644
--- a/sylvia-derive/src/input.rs
+++ b/sylvia-derive/src/input.rs
@@ -1,4 +1,4 @@
-use proc_macro2::TokenStream;
+use proc_macro2::{Span, TokenStream};
 use proc_macro_error::{emit_error, emit_warning};
 use quote::quote;
 use syn::{GenericParam, Ident, ItemImpl, ItemTrait, TraitItem};
@@ -7,13 +7,13 @@ use crate::associated_types::{AssociatedTypes, ItemType, EXEC_TYPE, QUERY_TYPE};
 use crate::executor::{ContractExecutor, InterfaceExecutor};
 use crate::interfaces::Interfaces;
 use crate::message::{
-    ContractApi, ContractEnumMessage, EnumMessage, GlueMessage, InterfaceApi, MsgVariants,
-    StructMessage,
+    ContractApi, ContractEnumMessage, EntryPoints, EnumMessage, GlueMessage, InterfaceApi,
+    MsgVariants, StructMessage,
 };
 use crate::multitest::{ContractMtHelpers, TraitMtHelpers};
 use crate::parser::attributes::msg::MsgType;
 use crate::parser::{
-    assert_new_method_defined, ContractErrorAttr, Custom, OverrideEntryPoint,
+    assert_new_method_defined, ContractErrorAttr, Custom, EntryPointArgs, OverrideEntryPoint,
     ParsedSylviaAttributes,
 };
 use crate::querier::{ContractQuerier, InterfaceQuerier};
@@ -339,3 +339,39 @@ impl<'a> ImplInput<'a> {
         ContractMtHelpers::new(item, generic_params, custom, override_entry_points.clone()).emit()
     }
 }
+
+pub struct EntryPointInput<'a> {
+    item: &'a ItemImpl,
+    args: EntryPointArgs,
+}
+
+impl<'a> EntryPointInput<'a> {
+    pub fn new(item: &'a ItemImpl, args: EntryPointArgs, attr_span: Span) -> Self {
+        let instantiate =
+            MsgVariants::<GenericParam>::new(item.as_variants(), MsgType::Instantiate, &[], &None);
+
+        if args.generics.len() != item.generics.params.len() {
+            emit_error!(
+                attr_span,
+                "Missing concrete types.";
+                note = "For every generic type in the contract, a concrete type must be provided in `#[entry_points(generics<T1, T2, ...>)]`.";
+            );
+        }
+
+        if instantiate.get_only_variant().is_none() {
+            emit_error!(
+                attr_span, "Missing instantiation message.";
+                note = "`sylvia::entry_points` requires exactly one method marked with `#[sv::msg(instantiation)]` attribute.";
+                note = "Make sure you implemented the `entry_points` macro above the `contract` macro."
+            );
+        }
+
+        Self { item, args }
+    }
+
+    pub fn process(&self) -> TokenStream {
+        let Self { item, args } = self;
+
+        EntryPoints::new(item, args).emit()
+    }
+}
diff --git a/sylvia-derive/src/lib.rs b/sylvia-derive/src/lib.rs
index b51149f..2fe5b9f 100644
--- a/sylvia-derive/src/lib.rs
+++ b/sylvia-derive/src/lib.rs
@@ -2,12 +2,15 @@
 //!
 //! Please refer to the [Sylvia-book](https://cosmwasm.github.io/sylvia-book/index.html) on how to use these macros.
 
-use input::{ImplInput, TraitInput};
+use crate::parser::EntryPointArgs;
+use input::{EntryPointInput, ImplInput, TraitInput};
 use proc_macro::TokenStream;
 use proc_macro2::TokenStream as TokenStream2;
 use proc_macro_error::proc_macro_error;
 use quote::quote;
+use strip_input::StripInput;
 use syn::fold::Fold;
+use syn::spanned::Spanned;
 use syn::{parse2, parse_quote, ItemImpl, ItemTrait, Path};
 
 mod associated_types;
@@ -26,11 +29,6 @@ mod strip_self_path;
 mod utils;
 mod variant_descs;
 
-use strip_input::StripInput;
-
-use crate::message::EntryPoints;
-use crate::parser::EntryPointArgs;
-
 #[cfg(not(test))]
 pub(crate) fn crate_module() -> Path {
     use proc_macro_crate::{crate_name, FoundCrate};
@@ -759,8 +757,8 @@ pub fn entry_points(attr: TokenStream, item: TokenStream) -> TokenStream {
 fn entry_points_impl(attr: TokenStream2, item: TokenStream2) -> TokenStream2 {
     fn inner(attr: TokenStream2, item: TokenStream2) -> syn::Result<TokenStream2> {
         let input: ItemImpl = parse2(item)?;
-        let attrs = EntryPointArgs::new(&attr, &input)?;
-        let expanded = EntryPoints::new(&input, attrs).emit();
+        let args = EntryPointArgs::new(&attr)?;
+        let expanded = EntryPointInput::new(&input, args, attr.span()).process();
 
         Ok(quote! {
             #input
diff --git a/sylvia-derive/src/message.rs b/sylvia-derive/src/message.rs
index a3a69ae..d44ac63 100644
--- a/sylvia-derive/src/message.rs
+++ b/sylvia-derive/src/message.rs
@@ -1264,11 +1264,11 @@ pub struct EntryPoints<'a> {
     override_entry_points: Vec<OverrideEntryPoint>,
     generics: Vec<&'a GenericParam>,
     where_clause: &'a Option<WhereClause>,
-    attrs: EntryPointArgs,
+    attrs: &'a EntryPointArgs,
 }
 
 impl<'a> EntryPoints<'a> {
-    pub fn new(source: &'a ItemImpl, attrs: EntryPointArgs) -> Self {
+    pub fn new(source: &'a ItemImpl, attrs: &'a EntryPointArgs) -> Self {
         let name = StripGenerics.fold_type(*source.self_ty.clone());
         let parsed_attrs = ParsedSylviaAttributes::new(source.attrs.iter());
         let override_entry_points = parsed_attrs.override_entry_point_attrs;
diff --git a/sylvia-derive/src/parser/entry_point.rs b/sylvia-derive/src/parser/entry_point.rs
index 87bceff..584eb92 100644
--- a/sylvia-derive/src/parser/entry_point.rs
+++ b/sylvia-derive/src/parser/entry_point.rs
@@ -3,7 +3,7 @@ use proc_macro_error::emit_error;
 use syn::parse::{Error, Nothing, Parse, ParseStream};
 use syn::punctuated::Punctuated;
 use syn::spanned::Spanned;
-use syn::{parse2, GenericArgument, ItemImpl, Path, Result, Token};
+use syn::{parse2, GenericArgument, Path, Result, Token};
 
 use super::extract_generics_from_path;
 
@@ -15,20 +15,12 @@ pub struct EntryPointArgs {
 }
 
 impl EntryPointArgs {
-    pub fn new(attr: &TokenStream2, source: &ItemImpl) -> Result<Self> {
+    pub fn new(attr: &TokenStream2) -> Result<Self> {
         let args: Self = parse2(attr.clone()).map_err(|err| {
             emit_error!(attr, err);
             err
         })?;
 
-        if args.generics.len() != source.generics.params.len() {
-            emit_error!(
-                attr.span(),
-                "Missing concrete types.";
-                note = "For every generic type in the contract, a concrete type must be provided in `#[entry_points(generics<T1, T2, ...>)]`.";
-            );
-        }
-
         Ok(args)
     }
 }
diff --git a/sylvia/src/into_response.rs b/sylvia/src/into_response.rs
index 8311ce4..a9f84cb 100644
--- a/sylvia/src/into_response.rs
+++ b/sylvia/src/into_response.rs
@@ -11,9 +11,7 @@ impl<C> IntoMsg<C> for SubMsg<Empty> {
         let msg = match self.msg {
             CosmosMsg::Wasm(wasm) => CosmosMsg::Wasm(wasm),
             CosmosMsg::Bank(bank) => CosmosMsg::Bank(bank),
-            #[cfg(feature = "staking")]
             CosmosMsg::Staking(staking) => CosmosMsg::Staking(staking),
-            #[cfg(feature = "staking")]
             CosmosMsg::Distribution(distribution) => CosmosMsg::Distribution(distribution),
             CosmosMsg::Custom(_) => Err(StdError::generic_err(
                 "Custom Empty message should not be sent",


Test patch:
diff --git a/sylvia/tests/ui.rs b/sylvia/tests/ui.rs
index bd72ecd..04bfa98 100644
--- a/sylvia/tests/ui.rs
+++ b/sylvia/tests/ui.rs
@@ -1,4 +1,5 @@
 #[test]
+#[ignore]
 fn ui() {
     let t = trybuild::TestCases::new();
     t.compile_fail("tests/ui/**/*.rs");
diff --git a/sylvia/tests/ui/macros/entry_points.rs b/sylvia/tests/ui/macros/entry_points.rs
index 36ceabb..84a1e9a 100644
--- a/sylvia/tests/ui/macros/entry_points.rs
+++ b/sylvia/tests/ui/macros/entry_points.rs
@@ -60,4 +60,23 @@ pub mod missing_generics {
     }
 }
 
+pub mod wrong_order {
+    use super::*;
+
+    pub struct Contract;
+
+    #[contract]
+    #[entry_points]
+    impl Contract {
+        pub fn new() -> Self {
+            Self
+        }
+
+        #[sv::msg(instantiate)]
+        fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
+            Ok(Response::new())
+        }
+    }
+}
+
 fn main() {}
diff --git a/sylvia/tests/ui/macros/entry_points.stderr b/sylvia/tests/ui/macros/entry_points.stderr
index 8bf7e60..7548a3d 100644
--- a/sylvia/tests/ui/macros/entry_points.stderr
+++ b/sylvia/tests/ui/macros/entry_points.stderr
@@ -17,3 +17,55 @@ error: Missing concrete types.
    |
 42 |     #[entry_points(generics<Empty>)]
    |                    ^^^^^^^^
+
+error: Missing instantiation message.
+
+         = note: `sylvia::entry_points` requires exactly one method marked with `#[sv::msg(instantiation)]` attribute.
+         = note: Make sure you implemented the `entry_points` macro above the `contract` macro.
+
+  --> tests/ui/macros/entry_points.rs:69:5
+   |
+69 |     #[entry_points]
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the attribute macro `entry_points` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0599]: no method named `instantiate` found for reference `&wrong_order::Contract` in the current scope
+  --> tests/ui/macros/entry_points.rs:76:12
+   |
+76 |         fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
+   |            ^^^^^^^^^^^ method not found in `&Contract`
+   |
+   = help: items from traits can only be used if the trait is in scope
+help: trait `Contract` which provides `instantiate` is implemented but not in scope; perhaps you want to import it
+   |
+68 +     use sylvia::cw_multi_test::Contract;
+   |
+
+error[E0599]: no function or associated item named `new` found for struct `wrong_order::Contract` in the current scope
+  --> tests/ui/macros/entry_points.rs:68:5
+   |
+66 |     pub struct Contract;
+   |     ------------------- function or associated item `new` not found for this struct
+67 |
+68 |     #[contract]
+   |     ^^^^^^^^^^^ function or associated item not found in `Contract`
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following traits define an item `new`, perhaps you need to implement one of them:
+           candidate #1: `ark_ec::hashing::HashToCurve`
+           candidate #2: `ark_ec::hashing::map_to_curve_hasher::MapToCurve`
+           candidate #3: `ark_ff::fields::field_hashers::HashToField`
+           candidate #4: `ark_poly::domain::EvaluationDomain`
+           candidate #5: `ark_poly::polynomial::multivariate::Term`
+           candidate #6: `crypto_common::KeyInit`
+           candidate #7: `crypto_common::KeyIvInit`
+           candidate #8: `curve25519_dalek::traits::VartimePrecomputedMultiscalarMul`
+           candidate #9: `digest::VariableOutput`
+           candidate #10: `digest::core_api::VariableOutputCore`
+           candidate #11: `digest::digest::Digest`
+           candidate #12: `digest::mac::Mac`
+           candidate #13: `itertools::adaptors::coalesce::CountItem`
+           candidate #14: `rand::distributions::uniform::UniformSampler`
+           candidate #15: `typenum::marker_traits::Bit`
+   = note: this error originates in the attribute macro `contract` (in Nightly builds, run with -Z macro-backtrace for more info)