Repository: rust
Issue: Confusing error when forgetting to break with value from loop-match
Labels: A-diagnostics,T-compiler

<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.

If you cannot produce a minimal reproduction case (something that would work in
isolation), please provide the steps or even link to a repository that causes
the problematic output to occur.
-->

Given the following code: <!-- Please provide a link to play.rust-lang.org -->

```rust
enum E {
    A(i32),
    B,
}

fn foo(e: E) -> Result<i32, &'static str> {
    let a = loop {
        match e {
            E::A(a) => a,
            E::B => {
                return Err("b")
            },
        }
    };
    Ok(a)
}
```

The current output is:

```
error[[E0308]](https://doc.rust-lang.org/stable/error-index.html#E0308): `match` arms have incompatible types
  --> src/lib.rs:11:17
   |
8  | /         match e {
9  | |             E::A(a) => a,
   | |                        - this is found to be of type `i32`
10 | |             E::B => {
11 | |                 return Err("b")
   | |                 ^^^^^^^^^^^^^^^ expected `i32`, found `()`
12 | |             },
13 | |         }
   | |_________- `match` arms have incompatible types

warning: unreachable expression
  --> src/lib.rs:15:5
   |
7  |       let a = loop {
   |  _____________-
8  | |         match e {
9  | |             E::A(a) => a,
10 | |             E::B => {
...  |
13 | |         }
14 | |     };
   | |_____- any code following this expression is unreachable
15 |       Ok(a)
   |       ^^^^^ unreachable expression
   |
   = note: `#[warn(unreachable_code)]` on by default

For more information about this error, try `rustc --explain E0308`.
warning: `playground` (lib) generated 1 warning
error: could not compile `playground` due to previous error; 1 warning emitted
```

The "expected `i32`, found `()`" suggestion is bogus, because the `return` actually has "never" type, and it's perfectly valid in a match that expects `i32`, e.g. the same code without `loop` works fine:

```rust
enum E {
    A(i32),
    B,
}

fn foo(e: E) -> Result<i32, &'static str> {
    let a = {
        match e {
            E::A(a) => a,
            E::B => {
                return Err("b")
            },
        }
    };
    Ok(a)
}
```

<!-- The following is not always necessary. -->
Ideally the output should look like:

If possible to guess from context, it should tell me that I forgot to use `break a`  instead of just `a` in the first branch. Otherwise not sure what the end result should be, but it definitely shouldn't say that `return` has a non-never type as that leads the developer down the wrong path.

<!--
If the problem is not self-explanatory, please provide a rationale for the
change.
-->

<!--
If dramatically different output is caused by small changes, consider also
adding them here.

If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions. The output might also be
different depending on the Edition.
-->