mockall icon indicating copy to clipboard operation
mockall copied to clipboard

bug(mock!): Error E0412, Cannot find type K in this scope when using mock! macro

Open gate2017aloy opened this issue 1 year ago • 3 comments

I encountered an issue while using the mockall library to create a mock implementation for store operations in my Rust project. The error message I received is: error[E0412]: cannot find type K in this scope

use substreams::store::{StoreDelete, StoreNew, StoreSet};
use substreams::{store::StoreGet, Hex};
use mockall::predicate::*;
use mockall::*;
use pretty_assertions::assert_eq;
use prost::Message;

mock! {
    /// Mock implementation for store operations used in testing.
    pub StoreSetProto<T: Default + prost::Message + 'static> {}

    impl<T: prost::Message + 'static + Default> StoreNew for StoreSetProto<T> {
        fn new() -> Self;
    }

    impl<T: prost::Message + 'static + Default> StoreDelete for StoreSetProto<T> {
        #[cfg_attr(concretize)]
        fn delete_prefix(&self, ordinal: i64, key: &String);
    }

    impl<T: Default + prost::Message + 'static> StoreSet<T> for StoreSetProto<T> {
        #[cfg_attr(concretize)]
        fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: &T);

        #[cfg_attr(concretize)]
        fn set_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &T);
    }
}

gate2017aloy avatar Dec 11 '24 13:12 gate2017aloy

@gate2017aloy could you please provide some more information? A minimal example to reproduce the problem would be great. The example you provided can't even compile, because it doesn't include definitions for the StoreNew, StoreSet, and StoreDelete traits. Also, which section of code is triggering that error? The compiler should tell you.

asomers avatar Dec 11 '24 14:12 asomers

@gate2017aloy could you please provide some more information? A minimal example to reproduce the problem would be great. The example you provided can't even compile, because it doesn't include definitions for the StoreNew, StoreSet, and StoreDelete traits. Also, which section of code is triggering that error? The compiler should tell you.

Hi @asomers

We are trying to mock StoreSetProto of substreams::store

You can refer to the dependencies below

  • substreams = "0.5.22"
  • substreams-ethereum = "0.9.13"
  • mockall = "0.13.0"
  • prost = '^0.11.0'
  • prost-types = '0.11.0'
  • pretty_assertions = "1.4.1"

The compile time error is seen in the set_many method when mocking the StoreSet trait for StoreSetProto

    impl<T: Default + prost::Message + 'static> StoreSet<T> for StoreSetProto<T> {
        #[cfg_attr(concretize)]
        fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: &T);

        #[cfg_attr(concretize)]
        fn set_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &T);
    }

The error as mentioned above error[E0412]: cannot find type K in this scope

gate2017aloy avatar Dec 19 '24 07:12 gate2017aloy

That's still not a complete example. If you think that Mockall has a bug, could you please provide a minimal example? That is, a self-contained example that doesn't rely on external crates and does not contain methods irrelevant to the issue at hand?

asomers avatar Dec 19 '24 15:12 asomers

I am having a similar issue with concretize, although I'm using automock not mock!. Here is a minimal reproduction of the issue

#[cfg_attr(test, mockall::automock)]
pub trait Foo {
    #[cfg_attr(test, mockall::concretize)]
    fn foo<T: AsRef<str> + Send>(&self, input: Option<T>);
}

#[cfg(test)]
mod test {
    use crate::{Foo as _, MockFoo};

    #[test]
    fn foo() {
        let mut mock = MockFoo::new();
        mock.expect_foo().return_const(());
        mock.foo(Some("foo"));
    }
}

with the error

error[E0412]: cannot find type `T` in this scope
 --> src/lib.rs:4:55
  |
4 |     fn foo<T: AsRef<str> + Send>(&self, input: Option<T>);
  |                                                       ^ not found in this scope

It seems to happen whenever the parameter is a generic type that the type parameter is being passed to. So the Vec<K> in @gate2017aloy's example.

samkottler avatar Oct 14 '25 13:10 samkottler

@samkottler's argument is correct. Currently, #[concretize] only works with a select few types: T, &T, &mut T, and &[T]. It could be made to work with Option<T>, too. But working with arbitrary nested generic types would be hard. The code is in mockall_derive/src/lib.rs , in the function concretize_args, if you want to give it a try.

asomers avatar Oct 14 '25 14:10 asomers

I'm taking a look. I think concretize_args would just need to check if the argument type is Type::Path and then recursively rewrite the segments. I haven't done much syn and proc macros but I'll see what I can do.

samkottler avatar Oct 14 '25 14:10 samkottler

Alright. I've been working on this for a few hours and I see the problem. I don't see a better way to do it than some unsafe stuff with raw pointers, and I'm not comfortable enough with my abilities at this point to get that correct.

samkottler avatar Oct 14 '25 18:10 samkottler