mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-07 01:05:39 +03:00
fb6d93917e
Not linting irrefutable_let_patterns on let chains *[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust/pull/146832)* # Description this PR makes the lint `irrefutable_let_patterns` not check for `let chains`, only check for single `if let`, `while let`, and `if let guard`. # Motivation Since `let chains` were stabilized, the following code has become common: ```rust fn max() -> usize { 42 } fn main() { if let mx = max() && mx < usize::MAX { /* */ } } ``` This code naturally expresses "please call that function and then do something if the return value satisfies a condition". Putting the let binding outside the if would be bad as then it remains in scope after the if, which is not the intent. Current Output: ```bash warning: leading irrefutable pattern in let chain --> src/main.rs:7:8 | 7 | if let mx = max() && mx < usize::MAX { | ^^^^^^^^^^^^^^ | = note: this pattern will always match = help: consider moving it outside of the construct = note: `#[warn(irrefutable_let_patterns)]` on by default ``` Another common case is progressively destructuring a struct with enum fields, or an enum with struct variants: ```rust struct NameOfOuterStruct { middle: NameOfMiddleEnum, other: (), } enum NameOfMiddleEnum { Inner(NameOfInnerStruct), Other(()), } struct NameOfInnerStruct { id: u32, } fn test(outer: NameOfOuterStruct) { if let NameOfOuterStruct { middle, .. } = outer && let NameOfMiddleEnum::Inner(inner) = middle && let NameOfInnerStruct { id } = inner { /* */ } } ``` Current Output: ```bash warning: leading irrefutable pattern in let chain --> src\main.rs:17:8 | 17 | if let NameOfOuterStruct { middle, .. } = outer | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this pattern will always match = help: consider moving it outside of the construct = note: `#[warn(irrefutable_let_patterns)]` on by default warning: trailing irrefutable pattern in let chain --> src\main.rs:19:12 | 19 | && let NameOfInnerStruct { id } = inner | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this pattern will always match = help: consider moving it into the body ``` To avoid the warning, the readability would be much worse: ```rust fn test(outer: NameOfOuterStruct) { if let NameOfOuterStruct { middle: NameOfMiddleEnum::Inner(NameOfInnerStruct { id }), .. } = outer { /* */ } } ``` # related issue * rust-lang/rust#139369 # possible questions 1. Moving the irrefutable pattern at the head of the chain out of it would cause a variable that was intended to be temporary to remain in scope, so we remove it. However, should we keep the check for moving the irrefutable pattern at the tail into the body? 2. Should we still lint `entire chain is made up of irrefutable let`? --- This is my first time contributing non-documentation code to Rust. If there are any irregularities, please feel free to point them out. : )