FizzBazer
FizzBazer

Reputation: 367

Error: unable to infer enough type information about `_`; type annotations or generic parameter binding required

Apologies for the generic title.

Here is some example code:

use std::marker::PhantomData;

pub trait Foo {
    fn foo(&self);
}

pub trait Bar<A: Foo> {
    fn bar(&self, a: A);
}

pub struct Test<A, B>
    where A: Foo,
          B: Bar<A>
{
    _phantom_r: PhantomData<A>,
    bars: Vec<B>,
}

impl<A, B> Test<A, B>
    where A: Foo,
          B: Bar<A>
{
    pub fn new() -> Test<A, B> {
        Test {
            _phantom_r: PhantomData,
            bars: Vec::new(),
        }
    }

    pub fn add_bar(&mut self, b: B) {
        self.bars.push(b);
    }
}

fn main() {
    let t = Test::new();
}

(Playground)

The error is:

<anon>:32:13: 36:22 error: unable to infer enough type information about `_`; type annotations or generic parameter binding required [E0282]
<anon>:32     let t = Test::new();

I'm quite confused on what Rust is having trouble inferring the trait types, and how I can specify what it wants. That is, I'm not sure if this is right, because then I run into Sized issues:

let t = Test::new() as Test<Foo,Bar<Foo>>;

error:

<anon>:36:28: 36:46 error: the trait `core::marker::Sized` is not implemented for the type `Foo` [E0277]
<anon>:36     let t = Test::new() as Test<Foo,Bar<Foo>>;

I have two main questions:

  1. Why is Rust unable to infer the trait types of Test<A,B<A>>?
  2. What is the solution to make this code work?

Upvotes: 0

Views: 1431

Answers (3)

FizzBazer
FizzBazer

Reputation: 367

A note about the accepted answer - The accepted answer covers the problem with identifying traits, however there are some comments within that thread that explain additional details with this question. I'm summarizing one of them here for ease of reading (since comments are a bit hard to read).

Static Dispatch (which is used when you us a Trait like in the above code) will not work with multiple concrete types on a vector.

For example, take this example:

trait Foo {
    fn method(&self) -> String;
}
impl Foo for u8 {
    fn method(&self) -> String {
        format!("u8: {}", *self)
    }
}

impl Foo for String {
    fn method(&self) -> String {
        format!("string: {}", *self)
    }
}

struct Test<T: Foo> {
    foos: Vec<T>,
}
impl<T:Foo> Test<T> {
    pub fn do_something(&self, x: T) {
        self.foos.push(x);
    }
}

fn main() {
    let x = 5u8;
    let y = "Hello".to_string();

    let t = Test {foos:Vec::new()};
    t.do_something(x);
    t.do_something(y);
}

This will not work, because while do_something() could use Static Dispatch, Test::foos cannot. If we instead changed Test to:

struct Test {
}
impl Test {
    pub fn do_something<T: Foo>(&self, x: T) {
        x.method();
    }
}

It will work. The main() function did not need to change at all (aside from removing the vector), it entirely had to do with the Vector causing static dispatch (apparently) to not work.

In this case, i believe Dynamic Dispatch will work - but i'm not familiar enough with it just yet to give any in depth answer/example here. Hope this helps future readers.

Upvotes: 0

Shepmaster
Shepmaster

Reputation: 431689

You can boil the first error down to this:

fn main() {
    let v = Vec::new();
}

The problem here is that the compiler has no way to determine what the concrete type will be contained by the vector. In your case, you create a structure (Test) that can be created without passing in concrete types for A and B, but the underlying reasoning is the same.

The second issue is related. Neither Foo nor Bar are concrete types with a size known at compile time. Trying to use them in a location that requires a fixed size (represented by the Sized trait) will fail.

When you instantiate a type, the size of the type must be known and that's done by providing concrete types in place of the generic type parameters.

Upvotes: 0

Chris Emerson
Chris Emerson

Reputation: 14051

The short answer is that you haven't told it what type to use.

Paraphrasing your declarations:

pub trait Foo {}

"There is a trait Foo"

pub trait Bar<A: Foo> {}

"If you give me a type A which implements Foo, I can give you a trait Bar<A>."

pub struct Test<A, B>
    where A: Foo,
          B: Bar<A> {}

"If you give me types A, which implements Foo, and B, which implements Bar<A>, I'll give you a type Test<A,B>.

let t = Test::new();

"Make me a Test". This is the problem - Test isn't a type, it's a template for making a type given two other types (with some restrictions). In the example above you haven't provided any such types, just narrowed down what such types might be like.

To actually use Test, you need to provide the types:

struct MyA {}
impl Foo for MyA {
    fn foo(&self) { println!("MyA::foo"); }
}

struct MyB {}
impl Bar<MyA> for MyB {
    fn bar(&self, a: MyA) { println!("MyB::bar"); }

}

fn main() {
    let test = Test::<MyA, MyB>::new();
}

(Playground)

Upvotes: 6

Related Questions