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

trait A is not implemented for Box<dyn A> #363

Closed
frank-king opened this issue Feb 24, 2022 · 2 comments · Fixed by #380
Closed

trait A is not implemented for Box<dyn A> #363

frank-king opened this issue Feb 24, 2022 · 2 comments · Fixed by #380

Comments

@frank-king
Copy link

Hi folks, I met a compile error when doing this:

trait A { }

trait B: A {
    fn as_a(&self) -> &dyn A;
}


mockall::mock! {
    Foo {}
    impl A for Foo {}
    impl B for Foo {
        fn as_a(&self) -> &dyn A;
    }
}

The compile error is:

error[E0277]: the trait bound `Box<dyn A>: A` is not satisfied
  --> src/lib.rs:11:1
   |
11 | / mockall::mock! {
12 | |     Foo {}
13 | |     impl A for Foo {}
14 | |     impl B for Foo {
15 | |         fn as_a(&self) -> &dyn A;
16 | |     }
17 | | }
   | |_^ the trait `A` is not implemented for `Box<dyn A>`
   |
   = note: required for the cast to the object type `dyn A`
   = note: this error originates in the macro `mockall::mock` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0277`.
error: could not compile `mocktest` due to previous error

I ran cargo expand to see what was happening, and find that:

impl __mock_MockFoo_B::__as_a::Expectation {
    /// Call this [`Expectation`] as if it were the real method.
    pub(in super::super) fn call(&self) -> &Box<dyn A> {
         /* ... */
    }
}
// ...
impl B for MockFoo {
    fn as_a(&self) -> &dyn A {
        let no_match_msg = /* something irrelavent ... */;
        self.B_expectations.as_a.call().expect(&no_match_msg)
    }
}

Here Expectation::call returns &Box<dyn A> but B::as_a requires &dyn A, and Box<dyn A>: A is not satisfied.

The solution is simple. I just add something like this:

impl<T: A + ?Sized> A for Box<T> {}

Then it compiles.


But is it possible to make this change in the generated code in MockFoo::as_a?

-        self.B_expectations.as_a.call().expect(&no_match_msg)
+        &*self.B_expectations.as_a.call().expect(&no_match_msg)

After that, there is no extra impl<T: A + ?Sized> A for Box<T> {} needed.

@asomers
Copy link
Owner

asomers commented Feb 24, 2022

Yeah, I think that will work. Since you've already delved in so far, would you like to submit a PR? You can extend the test case that's already in mockall/tests/mock_return_dyn_trait.rs .

@frank-king
Copy link
Author

No problem. I'll try opening a PR later.

frank-king pushed a commit to frank-king/mockall that referenced this issue Feb 25, 2022
frank-king pushed a commit to frank-king/mockall that referenced this issue Feb 25, 2022
frank-king pushed a commit to frank-king/mockall that referenced this issue Feb 25, 2022
onalante-msft pushed a commit to onalante-msft/mockall that referenced this issue May 5, 2022
onalante-msft pushed a commit to onalante-msft/mockall that referenced this issue May 7, 2022
* fix `Box<dyn A>: A` required in returning `&dyn A` for asomers#363

* Tweak trait object return test

* Update changelog

* Add return value description for dedynify
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants