Conflicting impls for different FnMuts


#1

I’ve got a trait with one method and for convenience I want to implement it for any closure. The trait looks somewhat like this:

pub trait Foo {
    fn run(&mut self) -> Result<(), Error>;
}

With the generic FnMut impl looking like this:

impl<F> Foo for F
where F: FnMut() -> Result<(), Error>
{
    fn run(&mut self) -> Result<(), Error> {
        self()
    }
}

However there are some times when you statically know your F will never fail, so I thought I’d also create implement the trait for functions which don’t return anything.

impl<F> Foo for F
where F: FnMut()  // <- notice the different return type
{
    fn run(&mut self) -> Result<(), Error> {
        self()
    }
}

But then when you actually try to compile this you get a “conflicting implementation” error. Does anyone know why we get conflicting implementation errors when the two F types have different signatures?

Seeing as this use case is quite intuitive and should work,would this be a bug in the Fn* traits (which are still experimental), how the compiler desugars the parenthesis notation for a Fn* trait, or maybe even coherence?


#2

It’s a general restriction; the compiler doesn’t consider associated types when deciding if impls could overlap, and the return type of the Fn* traits are associated types.

trait Tr {
    type U;
}

trait X {}

impl<T> X for T where T: Tr<U=()> {}
impl<T> X for T where T: Tr<U=i32> {}

This fails to compile with:

error[E0119]: conflicting implementations of trait `X`:
 --> src/main.rs:8:1
  |
7 | impl<T> X for T where T: Tr<U=()> {}
  | --------------------------------- first implementation here
8 | impl<T> X for T where T: Tr<U=i32> {}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation

#3

Thanks, that’s pretty much what I assumed was happening with FnMut::Output. Do you know where I could find out more about this? I’m not an expert on the internals of the trait system and coherence, but I feel like it’s reasonable to want to do something like this.


#4

I vaguely recall a blog post a while ago about the orphan rules, but nothing more specific comes to mind.