Conditional tuple assignment type mismatch


#1
fn main() 
{
  let (foo, bar): (i32, i32) = {
    for i in 0..9
    {
      let x = i % 2;

      if x != 0
      {
        Some((i, x))
      } 
    }
    None
  }.expect("err");

  println!("{:?} {:?}", foo, bar);
}

This is simplified example of a bigger code piece.
It compiles with the error:

main.rs:10:9: 10:21 error: mismatched types [E0308]
main.rs:10         Some((i, x))
                   ^~~~~~~~~~~~
main.rs:10:9: 10:21 help: run `rustc --explain E0308` to see a detailed explanation
main.rs:10:9: 10:21 note: expected type `()`
main.rs:10:9: 10:21 note:    found type `std::option::Option<(_, _)>`

Now as I see the branching paths are clear:
Exit the block in the loop with Some((i,x)) if the condition happens once or go through the loop range and return None (which ends in panic).
The compiler however begs to disagree. Anyone knows why?


#3

Your loop doesn’t exit early. You want to break out of the loop and use Some(...) as the result of the outer block, but there’s no control flow construct that would allow this in Rust.

Even if the loop did exit early at Some(...), normal control flow would still see the None and use that as the block’s result.

The compiler complains because the if expression needs to have a type of () if there’s no else block to supply an alternate value of the same type.


#4

Until now I tough the result expression at a blocks end would automatically be “caught” by an assignment somewhere in outer scopes.

Thanks for clarifying that it doesn’t go that far.

For completeness’ sake a workaround for the example above:

fn main() 
{
  let (foo, bar): (i32, i32) = 
  {
    let mut val = None;

    for i in 0..9
    {
      let x = i % 2;

      if x != 0
      {
        val = Some((i, x));
        break;
      } 
    }
    val
  }.expect("err");

  println!("{:?} {:?}", foo, bar);
}

#5

This is true for most blocks (but has nothing to do with assignments), but not for loops. Currently loops always have a value of (), although there are proposals to make at least loop {} result in a different value with a break expr statement.