Generics mismatched types

Why can this code not compile? Shouldn’t I be able to pass &str as parameter here?

struct S<T: AsRef<str>>{
    t: T
}

fn bar<T: AsRef<str>>(t: T) -> S<T>{
    S{t}
}

fn foo<T: AsRef<str>>(t: T) -> S<T> {
    bar("b")
}

fn main() {
    foo("a");
}

Error:

error[E0308]: mismatched types
  --> src/main.rs:10:9
   |
9  | fn foo<T: AsRef<str>>(t: T) -> S<T> {
   |        - this type parameter
10 |     bar("b")
   |     --- ^^^ expected type parameter `T`, found `&str`
   |     |
   |     arguments to this function are incorrect
   |
   = note: expected type parameter `T`
                   found reference `&'static str`
help: the return type of this call is `&'static str` due to the type of the argument passed
  --> src/main.rs:10:5
   |
10 |     bar("b")
   |     ^^^^---^
   |         |
   |         this argument influences the return type of `bar`
note: function defined here
  --> src/main.rs:5:4
   |
5  | fn bar<T: AsRef<str>>(t: T) -> S<T>{
   |    ^^^                ----

>Solution :

Rust requires that generics typecheck correctly without having concrete types plugged in. (This is unlike C++.)

Look at foo in detail but rename its template parameter to avoid confusion:

fn foo<U: AsRef<str>>(t: U) -> S<U> {
    bar("b")
}

You call bar("b") and return its result. bar("b") instantiates to bar<&'static str>("b"), which returns S<&static str>, independently of what U is.

This is not correct, because you have no guarantee that foo needs to return a S<&static str>, because you don’t control its template argument.

For example, if I were to call foo("a".to_string()), I would instantiate foo<String>, which returns S<String> – and yet your implementation still tries to return a S<&'static str>.

That’s why the compiler rejects your code beforehand.

The error message is unfortunately a bit misleading. You see, Rust deduces types both from arguments and also result usage.

Because you return the result of bar from foo, the compiler deduces that bar needs to return S<U>, and therefore bar also needs to take a U as the argument, but you’re passing a &'static str, which may or may not be the same as U. And so you get the type mismatch reported on the argument instead of the result.

Leave a Reply