Summary
redundant_pattern_matching suggests turning matches!(x, Pattern if guard) into x.is_some() && guard, but it doesn't put that replacement in parentheses. So when the matches!(...) is used somewhere that binds tighter than &&, running cargo clippy --fix breaks the code. After a ! or in a == false comparison it still compiles but now computes something different; as the receiver of a method call or in an as cast it stops compiling.
Parentheses are already added around the receiver and around the guard on their own (#11175, #13906, #17116), but never around the whole x.is_some() && guard, so the surrounding operator ends up applying to just the x.is_some() part.
Reproducer
Code:
fn f(x: Option<i32>, cond: bool) -> bool {
!matches!(x, Some(_) if cond)
}
fn main() {
// `matches!(Some(1), Some(_) if false)` is `false`, so this prints `true`.
println!("{}", f(Some(1), false));
}
Running cargo clippy --fix rewrites it to:
fn f(x: Option<i32>, cond: bool) -> bool {
!x.is_some() && cond
}
which now reads as (!x.is_some()) && cond, so f(Some(1), false) returns false instead of true. The fix was applied automatically and silently changed the result.
Current output (the help: try: text replaces the highlighted matches!(…)):
warning: redundant pattern matching, consider using `is_some()`
--> src/main.rs:2:6
|
2 | !matches!(x, Some(_) if cond)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some() && cond`
Putting that back where the matches!(…) was gives !x.is_some() && cond, which is no longer the same expression.
Desired output. The whole && should be parenthesized when the surrounding expression binds tighter than &&:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!(x.is_some() && cond)`
The same thing happens in every context that binds tighter than &&, e.g.:
let _ = matches!(x, Some(_) if cond) == false; // → x.is_some() && cond == false (still compiles, now means `&& (cond == false)`)
let _ = matches!(x, Some(_) if cond).then(|| 1); // → x.is_some() && cond.then(|| 1) (no longer compiles: `bool && Option<_>`)
let _ = matches!(x, Some(_) if cond) as u8; // → x.is_some() && cond as u8 (no longer compiles: `bool && u8`)
The other way round, a plain statement, an if/while condition, a function argument, or an operand of &&/|| is fine as it is and shouldn't get extra parentheses (e.g. let _ = matches!(x, Some(_) if cond); should stay x.is_some() && cond).
Version
rustc 1.98.0-nightly (485ec3fbc 2026-06-10)
binary: rustc
commit-hash: 485ec3fbcc12fa14ef6596dabb125ad710499c9e
commit-date: 2026-06-10
host: aarch64-apple-darwin
release: 1.98.0-nightly
LLVM version: 22.1.6
Additional Labels
@rustbot label +I-suggestion-causes-error
@rustbot claim
Summary
redundant_pattern_matchingsuggests turningmatches!(x, Pattern if guard)intox.is_some() && guard, but it doesn't put that replacement in parentheses. So when thematches!(...)is used somewhere that binds tighter than&&, runningcargo clippy --fixbreaks the code. After a!or in a== falsecomparison it still compiles but now computes something different; as the receiver of a method call or in anascast it stops compiling.Parentheses are already added around the receiver and around the guard on their own (#11175, #13906, #17116), but never around the whole
x.is_some() && guard, so the surrounding operator ends up applying to just thex.is_some()part.Reproducer
Code:
Running
cargo clippy --fixrewrites it to:which now reads as
(!x.is_some()) && cond, sof(Some(1), false)returnsfalseinstead oftrue. The fix was applied automatically and silently changed the result.Current output (the
help: try:text replaces the highlightedmatches!(…)):Putting that back where the
matches!(…)was gives!x.is_some() && cond, which is no longer the same expression.Desired output. The whole
&&should be parenthesized when the surrounding expression binds tighter than&&:The same thing happens in every context that binds tighter than
&&, e.g.:The other way round, a plain statement, an
if/whilecondition, a function argument, or an operand of&&/||is fine as it is and shouldn't get extra parentheses (e.g.let _ = matches!(x, Some(_) if cond);should stayx.is_some() && cond).Version
Additional Labels
@rustbot label +I-suggestion-causes-error
@rustbot claim