Cannot Infer Type of Vec of `mpsc::Sender<>`

I realize this question or similar questions probably gets asked a lot, but I think this one is a bit unique.

I am attempting to pass messages between threads using mpsc channels and in order to send data from the controller thread back to each requester thread, I use a vector of mpsc::Senders to hold a unique sender for each thread.

I am getting an error on the first match branch, specifically on the section tx_channels[thread_id] which simply says cannot infer type. No other suggestions from clippy or cargo.

The second match branch is not erroring. I can't tell if this is because it is working, or because the first match branch is breaking things so badly that the compiler can't continue.

As far as I can tell, this should be Sender<ThreadResponse> as defined in the let tx_channels = ... line, but the compiler is not picking this up.

I am also at a loss as to how to tell the compiler what type it should be, as tx_channels[thread_id]::<mpsc::Sender<ThreadResponse>>.send(ThreadResponse::AllRecipes(recipes.clone())) (Turbofish syntax) just gets me an error about how the compiler is expecting a different symbol.

    // TODO: add this into the config file
    let num_threads: usize = 4;
    let mut join_guards = Vec::with_capacity(num_threads+1);
    let mut tx_channels: Vec<mpsc::Sender<ThreadResponse>> = Vec::with_capacity(num_threads);

    // spawn data owner thread
    join_guards.push(thread::spawn(move || {
        let mut recipes = recipes.clone();
        loop {
            // TODO: fix usage of unwrap here
           let (thread_id, message) = rx.recv().unwrap();
           match message {
                ThreadMessage::AllRecipes => tx_channels[thread_id].send(ThreadResponse::AllRecipes(recipes.clone())),
                // TODO: properly handle the Option of HashMap.get() rather than unwrapping
                ThreadMessage::RecipeRO(recipe_id) => tx_channels[thread_id].send(ThreadResponse::Recipe(recipes.get(&recipe_id).unwrap().clone())),
                ThreadMessage::RecipeRW(recipe_id) => todo!()
           }
        }
    }
            
            ));

This is from Line 139 in the linked repo if you need more context.

I apologize for the formatting mess, since this isn't compiling, I can't get rustfmt to run.

Appreciate any assistance here.

Please run cargo check and paste the message it produces. Cargo never gives one-line output.


toxicsauce@the-machine:CookBookRSΩ cargo clippy
warning: unused import: `WidgetRef`
  --> src/tui/app.rs:15:9
   |
15 |         WidgetRef, Wrap,
   |         ^^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

warning: `cookbook-rs` (lib) generated 1 warning
    Checking cookbook-rs v0.0.1 (/home/toxicsauce/projects/src/github.com/sww1235/CookBookRS)
error[E0282]: type annotations needed
   --> src/main.rs:150:46
    |
150 | ...   ThreadMessage::AllRecipes => tx_channels[thread_id].send(ThreadResponse::AllRecipes(recipes.clone())),
    |                                    ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type

For more information about this error, try `rustc --explain E0282`.

The underlined element in the message is also highlighted as an error in VIM.

Fully qualified syntax here would look more like <T>::method(receiver, ...). Note the double colons ::, you probably received a syntax error for using a .

What if you change this line?

let (thread_id, message): (usize, ThreadMessage) = rx.recv().unwrap();

When changing that line to ThreadMessage::AllRecipes => tx_channels[thread_id]::<mpsc::Sender<ThreadResponse>>::send(ThreadResponse::AllRecipes(recipes.clone())),

I get the following error, either using :: or .

toxicsauce@the-machine:CookBookRSΩ cargo clippy
warning: unused import: `WidgetRef`
  --> src/tui/app.rs:15:9
   |
15 |         WidgetRef, Wrap,
   |         ^^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

warning: `cookbook-rs` (lib) generated 1 warning
    Checking cookbook-rs v0.0.1 (/home/toxicsauce/projects/src/github.com/sww1235/CookBookRS)
error: expected one of `,`, `.`, `?`, `}`, or an operator, found `::`
   --> src/main.rs:150:68
    |
150 | ...:AllRecipes => tx_channels[thread_id]::<mpsc::Sender<ThreadResponse>>::send(ThreadResponse::AllRecipes(recip...
    |                --                       ^^ expected one of `,`, `.`, `?`, `}`, or an operator
    |                |
    |                while parsing the `match` arm starting here

error: could not compile `cookbook-rs` (bin "cookbook-rs") due to 1 previous error

Rust is confused because:

  • A Vec can be indexed with either a usize or a range of usize. (e.g., it's valid to write something like tx_channels[0..1].
  • In order to figure out what you intended, rust needs to figure out what type thread_id is.
  • In order to figure out that, rust needs to figure out what type rx is.
  • You didn't annotate the type of rx, and you didn't annotate the type of the mpsc::channel() call on line 126 that created it. Rust gives up trying to figure this out, and produces an error.
1 Like

The correct turbofish syntax is:

<mpsc::Sender<ThreadResponse>>::send(&tx_channels[thread_id], ThreadResponse::AllRecipes(recipes.clone()))

I expect that using turbofish won't help in this case though.

1 Like

This change resolved the issue, and themathas's post explained what was causing it.

The error message was actually referring to the index of the Vec<> but how the error message was presented made it seem like the issue was with the value contained within the Vec<>

Much appreciated all for very quick and helpful responses!

The reason the error refers to the result of the indexing, is because Vec indexing is implemented via the SliceIndex trait. (See here.) Therefore, rust does the following reasoning:

  • Suppose that the type of thread_id is X.
  • The result of tx_channels[thread_id] has type <X as SliceIndex<[....]>>::Output.
  • The code attempts to call a method named send on the type <X as SliceIndex<[....]>>::Output. Such a method cannot be found, with the information rust has so far.
  • The rest of the code doesn't have additional information to figure out X. Rust emits an error pointing to the receiver of the send call, since that's where we last needed to know what type X is.
1 Like

Really appreciate the clear and concise explanations of the chain that causes the errors! Very helpful!

I've filed an issue for this confusing compiler error. "type annotations needed" on associated type in trait of unknown type should point to that unknown type · Issue #142334 · rust-lang/rust · GitHub

2 Likes