Description
use core::future::Future;
async fn select<A: Future, B: Future>(_: A, _: B) -> Result<A::Output, B::Output> {
todo!()
}
pub async fn wtf() -> ! {
let a = async { loop {} };
let b = async { loop {} };
match select(a, b).await {
Ok(x) => x,
Err(x) => x,
}
}
warns with unreachable_patterns
on both arms
warning: unreachable pattern
--> src/lib.rs:11:9
|
11 | Ok(x) => x,
| ^^^^^
|
= note: this pattern matches no values because `Result<!, !>` is uninhabited
= note: `#[warn(unreachable_patterns)]` on by default
but removing either doesn't actually compile
error[E0004]: non-exhaustive patterns: `Ok(_)` not covered
--> src/lib.rs:10:11
|
10 | match select(a, b).await {
| ^^^^^^^^^^^^^^^^^^ pattern `Ok(_)` not covered
|
note: `Result<(), !>` defined here
--> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:527:1
|
527 | pub enum Result<T, E> {
| ^^^^^^^^^^^^^^^^^^^^^
...
531 | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
| -- not covered
= note: the matched value is of type `Result<(), !>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
11 ~ Err(x) => x,
12 ~ Ok(_) => todo!(),
So this code seems "unfixable" with the new lint.
What's happening is the match arm is unreachable, but it still has the "side effect" of making the async block be inferred to Future<Output=!>
instead of Future<Output=()>
. So, if you remove it the future now gets inferred to return ()
, and the arm is not unreachable anymore.
In edition 2024 it Just Works if you write match select(a, b).await {}
, because the fallback is !
instead of ()
.
This seems a bit hard to mitigate in Edition 2021, it seems more like an unfortunate combination of the lint and the inference fallback more than a bug. I'm opening the issue anyway to share it, just in case anyone has an idea.