Can't infer type for generic function inside a tuple

Hi, I am a newbie. Here's a simplified version of my code:

trait Voice {
    fn say();
}

struct Cat;
impl Voice for Cat {
    fn say() {
        println!("meow!");
    }
}

struct Dog;
impl Voice for Dog {
    fn say() {
        println!("woof!");
    }
}

fn call_animal<T: Voice>() {
    T::say();
}

enum Animal {
    Cat,
    Dog,
}

fn main() {
    let animal = Animal::Cat;
    let name = match animal {
        Animal::Cat => "cat",
        Animal::Dog => "dog",
    };
    let func = match animal {
        Animal::Cat => call_animal::<Cat>,
        Animal::Dog => call_animal::<Dog>,
    };
    println!("{name} says:");
    func();
}

This compiles fine. However, if we replace the main function with the following:

fn main() {
    let animal = Animal::Cat;
    let (name, func) = match animal {
        Animal::Cat => ("cat", call_animal::<Cat>),
        Animal::Dog => ("dog", call_animal::<Dog>),
    };
    println!("{name} says:");
    func();
}

it won't compile:

   Compiling match-test v0.1.0 (/Users/untech/Documents/code/rust/match-test)
error[E0308]: `match` arms have incompatible types
  --> src/main.rs:32:24
   |
30 |       let (name, func) = match animal {
   |  ________________________-
31 | |         Animal::Cat => ("cat", call_animal::<Cat>),
   | |                        --------------------------- this is found to be of type `(&str, fn() {call_animal::<Cat>})`
32 | |         Animal::Dog => ("dog", call_animal::<Dog>),
   | |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(&str, fn() {call_animal::<Cat>})`, found `(&str, fn() {call_animal::<Dog>})`
33 | |     };
   | |_____- `match` arms have incompatible types
   |
   = note: expected tuple `(&_, fn() {call_animal::<Cat>})`
              found tuple `(&'static _, fn() {call_animal::<Dog>})`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `match-test` (bin "match-test") due to 1 previous error

Apparently, the compiler can't infer the common type for two generic functions.

Questions:

  1. Is this a problem in my code, or a compiler problem?
  2. If it's a compiler problem, is this a known compiler problem, or should I report it somehow?

Every function has a unique, unnameable type, so the fact that the compiler decides to coerce them to function pointers in the compiling version is more notable to me. This topic could be interpreted as "can't it do that in more situations", which would be this issue I believe.

As noted in the issue, you can make the cast yourself.

Edit: Or annotate the binding.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.