rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
96.35k stars 12.45k forks source link

Spurious and incorrect "irrefutable `if let` pattern" warning in the presence of or-patterns #102411

Open bstrie opened 1 year ago

bstrie commented 1 year ago

The following program:

fn main() {
    let x: Result<i32, i32> = Ok(42);
    if let Ok(_) | Err(_) = x {}
}

...compiles successfully, but produces a warning:

warning: irrefutable `if let` pattern
 --> src/main.rs:3:8
  |
3 |     if let Ok(_) | Err(_) = x {}
  |        ^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(irrefutable_let_patterns)]` on by default
  = note: this pattern will always match, so the `if let` is useless
  = help: consider replacing the `if let` with a `let`

..however, following the warning's advice to replace the if let with a let, resulting in the following program:

fn main() {
    let x: Result<i32, i32> = Ok(42);
    let Ok(_) | Err(_) = x;
}

..results in compilation failing with the following error:

error: top-level or-patterns are not allowed in `let` bindings
 --> src/main.rs:4:9
  |
3 |     let Ok(_) | Err(_) = x;
  |         ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Ok(_) | Err(_))`

In the future, if/when top-level or-patterns are allowed in let, then this warning would be correct. However, for the moment, this warning is mistaken, and should either not be emitted or should suggest the version wrapped in parentheses.

scottmcm commented 1 year ago

There is an alternative; you wrap the pattern in parens, as the help says:

fn main() {
    let x: Result<i32, i32> = Ok(42);
    let (Ok(_) | Err(_)) = x;
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=3f741264b0440f42e374a105993c0df8

bstrie commented 1 year ago

I've updated the issue, still a bit annoying though.

shanecelis commented 1 month ago

I had this issue for an enum with only one variant. When I tried to make a minimal example, I could not provoke it. The weird thing was, I changed it to a let no if and it still complained. And I even added the allow(irrefutable_let_patterns) and it would not stop showing the warning on cargo check (not clippy).

//! Failed reproduction of issue
pub enum Layer {
    Liquid { id: usize, volume: f32 },
}

/// The warning this used to provoke in my code that I could not force it to
/// issue in this minimal example with rustc v1.78.0 (9b00956e5 2024-04-29)
///
/// ```
/// warning: irrefutable `if let` pattern
///  --> src/level.rs:67:23
///   |
///67 |                   let Layer::Liquid { id, .. } = l;
///   |  _______________________^
///68 | |                 *id
///   | |____^
///   |
///   = note: this pattern will always match, so the `if let` is useless
///   = help: consider replacing the `if let` with a `let`
///   = note: `#[warn(irrefutable_let_patterns)]` on by default
/// ```
// #[allow(irrefutable_let_patterns)]
fn f(l: &Layer) -> Option<usize> {
    let Layer::Liquid { id, .. } = l;
    Some(*id)
}

fn main() {
    let l = Layer::Liquid { id: 0, volume: 0.0 };
    println!("{:?}", f(&l));
}