Skip to content

Comments

Not linting irrefutable_let_patterns on let chains#146832

Merged
rust-bors[bot] merged 1 commit intorust-lang:mainfrom
Natural-selection1:not-in-chains
Feb 21, 2026
Merged

Not linting irrefutable_let_patterns on let chains#146832
rust-bors[bot] merged 1 commit intorust-lang:mainfrom
Natural-selection1:not-in-chains

Conversation

@Natural-selection1
Copy link
Contributor

@Natural-selection1 Natural-selection1 commented Sep 21, 2025

View all comments

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:

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:

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:

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:

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:

fn test(outer: NameOfOuterStruct) {
    if let NameOfOuterStruct {
        middle: NameOfMiddleEnum::Inner(NameOfInnerStruct { id }),
        ..
    } = outer
    {
        /* */
    }
}

related issue

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.
: )

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Sep 21, 2025
@rustbot

This comment was marked as off-topic.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@traviscross traviscross added T-lang Relevant to the language team needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. I-lang-radar Items that are on lang's radar and will need eventual work or consideration. labels Sep 21, 2025
@rust-log-analyzer

This comment has been minimized.

@Natural-selection1 Natural-selection1 force-pushed the not-in-chains branch 2 times, most recently from ce66065 to e77a3c4 Compare September 21, 2025 11:02
@Natural-selection1 Natural-selection1 marked this pull request as ready for review September 21, 2025 11:07
@rustbot
Copy link
Collaborator

rustbot commented Sep 21, 2025

Some changes occurred in match checking

cc @Nadrieril

The Miri subtree was changed

cc @rust-lang/miri

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Sep 21, 2025
@Natural-selection1
Copy link
Contributor Author

It seems that only modifying tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs is needed to cover this change. Do I still need to add an additional new test?

@traviscross
Copy link
Contributor

It seems that only modifying tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs is needed to cover this change. Do I still need to add an additional new test?

All the lints seem to be removed in that test, but you'll want to ensure there are tests that cover the edges of what is still linted here.

@rustbot author

@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 21, 2025
@rustbot
Copy link
Collaborator

rustbot commented Sep 21, 2025

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rustbot rustbot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Sep 21, 2025
@rustbot rustbot unassigned lcnr Dec 9, 2025
@scottmcm
Copy link
Member

Huh, this lint actually just caught a mistake for me:
image

(But that'd also be handled well with a special-case "your TryFrom could be From" lint.)

@rust-bors

This comment has been minimized.

@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Jan 29, 2026
@rustbot
Copy link
Collaborator

rustbot commented Feb 19, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

inline rest of the check
try fix ci errors
inline in check_let
@Natural-selection1
Copy link
Contributor Author

I resolved the merge conflicts, can we proceed with merging this PR now?
I'm hoping to have it released together with Stabilize if let guards in version 1.95
: )

@Kobzol
Copy link
Member

Kobzol commented Feb 20, 2026

@rustbot ready

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Feb 20, 2026
@petrochenkov
Copy link
Contributor

@bors r+

@rust-bors
Copy link
Contributor

rust-bors bot commented Feb 20, 2026

📋 This PR cannot be approved because it currently has the following label: S-waiting-on-t-lang.

@petrochenkov petrochenkov removed S-waiting-on-t-lang Status: Awaiting decision from T-lang needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. labels Feb 20, 2026
@petrochenkov
Copy link
Contributor

@bors r+

@rust-bors
Copy link
Contributor

rust-bors bot commented Feb 20, 2026

📌 Commit 4f31ff8 has been approved by petrochenkov

It is now in the queue for this repository.

@rust-bors rust-bors bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 20, 2026
rust-bors bot pushed a commit that referenced this pull request Feb 21, 2026
…uwer

Rollup of 9 pull requests

Successful merges:

 - #146832 (Not linting irrefutable_let_patterns on let chains)
 - #146972 (Support importing path-segment keyword with renaming)
 - #152241 (For panic=unwind on Wasm targets, define __cpp_exception tag)
 - #152527 (Remove -Zemit-thin-lto flag)
 - #152769 (Do not cancel try builds after first job failure)
 - #152907 (Add tests for delegation generics)
 - #152455 (Remove the translation `-Z` options and the `Translator` type. )
 - #152813 (Skip the `use_existential_projection_new_instead` field in the `Debug` impl)
 - #152912 (Expose Span for all DefIds in rustc_public)
@rust-bors rust-bors bot merged commit fb6d939 into rust-lang:main Feb 21, 2026
11 checks passed
@rustbot rustbot added this to the 1.95.0 milestone Feb 21, 2026
rust-timer added a commit that referenced this pull request Feb 21, 2026
Rollup merge of #146832 - Natural-selection1:not-in-chains, r=petrochenkov

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

* #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.
: )
github-actions bot pushed a commit to rust-lang/miri that referenced this pull request Feb 22, 2026
…uwer

Rollup of 9 pull requests

Successful merges:

 - rust-lang/rust#146832 (Not linting irrefutable_let_patterns on let chains)
 - rust-lang/rust#146972 (Support importing path-segment keyword with renaming)
 - rust-lang/rust#152241 (For panic=unwind on Wasm targets, define __cpp_exception tag)
 - rust-lang/rust#152527 (Remove -Zemit-thin-lto flag)
 - rust-lang/rust#152769 (Do not cancel try builds after first job failure)
 - rust-lang/rust#152907 (Add tests for delegation generics)
 - rust-lang/rust#152455 (Remove the translation `-Z` options and the `Translator` type. )
 - rust-lang/rust#152813 (Skip the `use_existential_projection_new_instead` field in the `Debug` impl)
 - rust-lang/rust#152912 (Expose Span for all DefIds in rustc_public)
github-actions bot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request Feb 23, 2026
…uwer

Rollup of 9 pull requests

Successful merges:

 - rust-lang/rust#146832 (Not linting irrefutable_let_patterns on let chains)
 - rust-lang/rust#146972 (Support importing path-segment keyword with renaming)
 - rust-lang/rust#152241 (For panic=unwind on Wasm targets, define __cpp_exception tag)
 - rust-lang/rust#152527 (Remove -Zemit-thin-lto flag)
 - rust-lang/rust#152769 (Do not cancel try builds after first job failure)
 - rust-lang/rust#152907 (Add tests for delegation generics)
 - rust-lang/rust#152455 (Remove the translation `-Z` options and the `Translator` type. )
 - rust-lang/rust#152813 (Skip the `use_existential_projection_new_instead` field in the `Debug` impl)
 - rust-lang/rust#152912 (Expose Span for all DefIds in rustc_public)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. I-lang-radar Items that are on lang's radar and will need eventual work or consideration. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team

Projects

None yet

Development

Successfully merging this pull request may close these issues.