Skip to content

Fixes a case where collapsible_match suggested a transformation that changes runtime behavior.#16878

Merged
samueltardieu merged 3 commits intorust-lang:masterfrom
Souradip121:fix-collapsible-match-guard-semantics
Apr 20, 2026
Merged

Fixes a case where collapsible_match suggested a transformation that changes runtime behavior.#16878
samueltardieu merged 3 commits intorust-lang:masterfrom
Souradip121:fix-collapsible-match-guard-semantics

Conversation

@Souradip121
Copy link
Copy Markdown
Contributor

@Souradip121 Souradip121 commented Apr 17, 2026

Closes #16875

What was wrong

The lint suggested collapsing pattern => { if test { body } } into pattern if test => { body }. These are not equivalent. In the original, once pattern matches, the match exits regardless of test. In the suggestion, a failing guard allows fall-through to subsequent arms, which can match values that previously never reached them.

// Before (original)
match a {
    Some(_) => {
        if b == 0 { res = 1 }
    }
    _ if b == 1 => res = 2,  // unreachable when a is Some(_)
    _ => {}
}

// After (suggestion — WRONG, changes behavior)
match a {
    Some(_) if b == 0 => res = 1,
    _ if b == 1 => res = 2,  // now reachable when a is Some(_) and b != 0
    _ => {}
}

Fix

The if-guard collapsing is only safe when there are no non-wildcard arms between the current arm and the wildcard arm. The fix adds a check that all arms after the current one are "wild-like" (a bare _, a binding, or None, all without guards) before suggesting the transformation.

As a side effect, three #[expect(clippy::collapsible_match)] suppressions in clippy_lints/src/methods/mod.rs are removed. They had been added to suppress this exact false positive and are no longer needed.

Still lints correctly

When only wildcard arms follow, the transformation is safe and the lint still fires:

// This still lints — only `_ => {}` follows, fall-through is harmless
match a {
    Some(_) => {
        if b == 0 { res = 1 }  // triggers collapsible_match
    }
    _ => {}
}

changelog: [collapsible_match]: no longer suggests collapsing pattern => { if test { body } } into a match guard when non-wildcard arms follow, as this changes the semantics of the match.

Summary Notes

Managed by @rustbot—see help for details

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Apr 17, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 17, 2026

r? @dswij

rustbot has assigned @dswij.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: 7 candidates
  • 7 candidates expanded to 7 candidates
  • Random selection from Jarcho, dswij, llogiq, samueltardieu

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 17, 2026

Lintcheck changes for c7cadb6

Lint Added Removed Changed
clippy::collapsible_match 0 7 2

This comment will be updated if you push new changes

Comment thread clippy_lints/src/matches/collapsible_match.rs Outdated
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Apr 18, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 18, 2026

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

Co-authored-by: Samuel Tardieu <sam@rfc1149.net>
@Souradip121
Copy link
Copy Markdown
Contributor Author

@rustbot ready

@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 from the author. (Use `@rustbot ready` to update this status) labels Apr 18, 2026
Copy link
Copy Markdown
Member

@samueltardieu samueltardieu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rustbot label +beta-nominated
@rustbot note Beta-nomination

This fixes a I-suggestion-causes-bug regression in 1.95. This could even be backported in a point release for 1.95.1.

Cc @flip1995

View changes since this review

@rustbot rustbot added the beta-nominated Nominated for backporting to the compiler in the beta channel. label Apr 18, 2026
@samueltardieu samueltardieu added the I-suggestion-causes-bug Issue: The suggestion compiles but changes the code to behave in an unintended way label Apr 18, 2026
@profetia
Copy link
Copy Markdown
Member

Can you check if this also fixes #16716 and #16717? If not, can you borrow from #16749 to fix them? I'm thinking to put everything on this PR since it is beta nominated.

@Souradip121
Copy link
Copy Markdown
Contributor Author

Alright @profetia checking right now.

@samueltardieu
Copy link
Copy Markdown
Member

Please keep beta-nominated PR at minimal size, so that they are easy to review. Those PRs are merged very late into the beta cycle, almost right before the stable release, so they must be very very readable.

This one fixes a I-suggestion-causes-bug kind of problem which is more critical than I-suggestion-causes-error.

@samueltardieu
Copy link
Copy Markdown
Member

If not, can you borrow from #16749 to fix them? I'm thinking to put everything on this PR since it is beta nominated.

This is not a good idea.

@Souradip121
Copy link
Copy Markdown
Contributor Author

@samueltardieu @profetia should I push the new commits or not :)

@samueltardieu
Copy link
Copy Markdown
Member

@samueltardieu @profetia should I push the new commits or not :)

Not in this PR.

@Souradip121
Copy link
Copy Markdown
Contributor Author

@samueltardieu Alright, not doing it, kindly merge my PR then.

@samueltardieu
Copy link
Copy Markdown
Member

samueltardieu commented Apr 20, 2026

Given that's it's beta-nominated and possibly considered for stable backporting, I want to let a second maintainer a chance to have a look to it first.

Ping @rust-lang/clippy

@profetia
Copy link
Copy Markdown
Member

This PR now already fixes #16717. I will reopen #16749 for #16716 solely, after it is merged.

@samueltardieu samueltardieu added this pull request to the merge queue Apr 20, 2026
Merged via the queue into rust-lang:master with commit 87e4c91 Apr 20, 2026
13 checks passed
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Apr 20, 2026
ojeda added a commit to Rust-for-Linux/linux that referenced this pull request Apr 30, 2026
The `clippy::collapsible_match` lint [1] can make code harder to read
in certain cases [2], e.g.

      CLIPPY P rust/libmacros.so - due to command line change
    warning: this `if` can be collapsed into the outer `match`
      --> rust/pin-init/internal/src/helpers.rs:91:17
       |
    91 | /                 if nesting == 1 {
    92 | |                     impl_generics.push(tt.clone());
    93 | |                     impl_generics.push(tt);
    94 | |                     skip_until_comma = false;
    95 | |                 }
       | |_________________^
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match
       = note: `-W clippy::collapsible-match` implied by `-W clippy::all`
       = help: to override `-W clippy::all` add `#[allow(clippy::collapsible_match)]`
    help: collapse nested if block
       |
    90 ~             TokenTree::Punct(p) if skip_until_comma && p.as_char() == ','
    91 ~                 && nesting == 1 => {
    92 |                     impl_generics.push(tt.clone());
    93 |                     impl_generics.push(tt);
    94 |                     skip_until_comma = false;
    95 ~                 }
       |

The lint does not have much upside -- when the suggestion may be a good
one, it would still read fine when nested anyway. And it is the kind of
lint that may easily bias people to just apply the suggestion instead
of allowing it.

[ In addition, as Gary points out [3], the suggestion is also wrong [4] and
  in the process of being fixed [5], possibly for Rust 1.97.0:

  Link: https://lore.kernel.org/rust-for-linux/DI3YV94TH9I3.1SOHW51552497@garyguo.net/ [3]
  Link: rust-lang/rust-clippy#16875 [4]
  Link: rust-lang/rust-clippy#16878 [5]

    - Miguel ]

Thus just let developers decide on their own.

Cc: stable@vger.kernel.org # Needed in 6.12.y and later (Rust is pinned in older LTSs).
Link: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match [1]
Link: https://lore.kernel.org/rust-for-linux/CANiq72nWYJna_hdFxjQCQZK6yJBrr1Mb86iKavivV0U0BgufeA@mail.gmail.com/ [2]
Reviewed-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260426144201.227108-1-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

beta-nominated Nominated for backporting to the compiler in the beta channel. I-suggestion-causes-bug Issue: The suggestion compiles but changes the code to behave in an unintended way

Projects

None yet

Development

Successfully merging this pull request may close these issues.

collapsible_match suggestion change meaning

6 participants