What is this: expected `()`, found `Result<(), _>?

Hello. I'm new to Rust (but not programming), so I am really curious to know the explanation of very unexpected behaviour of compiler with triple return:

Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6901de626d769b2fb19ecb1fcb947588

    fn main() {
    	fn hydrate() -> Result<(), String> {
    		if 1 == 2 {
    			Ok(())
    		} else {
    			Err("error".to_string())
    		}
    		Ok(())
    	}
    }

I get these errors:

    error[E0308]: mismatched types
     --> src/main.rs:4:4
      |
    3 | /         if 1 == 2 {
    4 | |             Ok(())
      | |             ^^^^^^ expected `()`, found `Result<(), _>`
    5 | |         } else {
    6 | |             Err("error".to_string())
    7 | |         }
      | |_________- expected this to be `()`
      |
      = note: expected unit type `()`
                      found enum `Result<(), _>`
    help: you might have meant to return this value
      |
    4 |             return Ok(());
      |             ++++++       +
    
    error[E0308]: mismatched types
     --> src/main.rs:6:4
      |
    3 | /         if 1 == 2 {
    4 | |             Ok(())
    5 | |         } else {
    6 | |             Err("error".to_string())
      | |             ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Result<_, String>`
    7 | |         }
      | |_________- expected this to be `()`
      |
      = note: expected unit type `()`
                      found enum `Result<_, String>`

The error disappears when:

  1. Removing the last Ok(())
  2. Adding "return" in if branches

Why? LOL

  1. Why return fixes it? I don't have let with if, so it returns it anyway
  2. Why the compiler says like that? Who expects ()? The function expects Result<(), String>

And did anyone report it as a confusing error? I saw their fixing these types of errors according to their roadmap.

The if-else block is an expression statement with a block and no semicolon, and that's why it's expected to evaluate to ().

Without return, the if-else isn't in return position, so what the function expects is irrelevant. If you add a semicolon to make it compile, for example, the value the if-else evaluates to is just thrown away.

Maybe you read something like "values are returned out of if-else blocks". If so, they didn't mean an if-else without let is equivalent to this:

// return from containing function
return if condition { ... } else { ... }

They meant that the if-else block evaluates to a value based on the last expression of the blocks.

2 Likes

Ahhh I got it now! Thank you a lot! I think I didn't read about that carefully enough or forgot.

P.S. Should I suggest to make the error more clear on internals.? As making Rust more beginner-friendly?

You could chime in on this issue. In general for diagnostic suggestions you can just file a new issue if you don't find an existing one.

2 Likes