Skip to content

Commit 960863f

Browse files
committed
fix: equatable_if_let suggests wrongly when involving reference
1 parent f5d81a3 commit 960863f

File tree

4 files changed

+124
-2
lines changed

4 files changed

+124
-2
lines changed

clippy_lints/src/equatable_if_let.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,38 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T
6767
}
6868
}
6969

70+
/// Check if the pattern has any type mismatch that would prevent it from being used in an equality
71+
/// check. This can happen if the expr has a reference type and the corresponding pattern is a
72+
/// literal.
73+
fn contains_type_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
74+
let mut result = false;
75+
pat.walk(|p| {
76+
if result {
77+
return false;
78+
}
79+
80+
if p.span.in_external_macro(cx.sess().source_map()) {
81+
return true;
82+
}
83+
84+
let adjust_pat = match p.kind {
85+
PatKind::Or([p, ..]) => p,
86+
_ => p,
87+
};
88+
89+
if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id)
90+
&& adjustments.first().is_some_and(|first| first.is_ref())
91+
{
92+
result = true;
93+
return false;
94+
}
95+
96+
true
97+
});
98+
99+
result
100+
}
101+
70102
impl<'tcx> LateLintPass<'tcx> for PatternEquality {
71103
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
72104
if let ExprKind::Let(let_expr) = expr.kind
@@ -77,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
77109
let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
78110
let mut applicability = Applicability::MachineApplicable;
79111

80-
if is_structural_partial_eq(cx, exp_ty, pat_ty) {
112+
if is_structural_partial_eq(cx, exp_ty, pat_ty) && !contains_type_mismatch(cx, let_expr.pat) {
81113
let pat_str = match let_expr.pat.kind {
82114
PatKind::Struct(..) => format!(
83115
"({})",

tests/ui/equatable_if_let.fixed

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,39 @@ fn main() {
103103

104104
external!({ if let 2 = $a {} });
105105
}
106+
107+
mod issue8710 {
108+
fn str_ref(cs: &[char]) {
109+
if matches!(cs.iter().next(), Some('i')) {
110+
//~^ equatable_if_let
111+
} else {
112+
todo!();
113+
}
114+
}
115+
116+
fn i32_ref(cs: &[i32]) {
117+
if matches!(cs.iter().next(), Some(1)) {
118+
//~^ equatable_if_let
119+
} else {
120+
todo!();
121+
}
122+
}
123+
124+
fn enum_ref() {
125+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
126+
enum MyEnum {
127+
A(i32),
128+
B,
129+
}
130+
131+
fn get_enum() -> Option<&'static MyEnum> {
132+
todo!()
133+
}
134+
135+
if matches!(get_enum(), Some(MyEnum::B)) {
136+
//~^ equatable_if_let
137+
} else {
138+
todo!();
139+
}
140+
}
141+
}

tests/ui/equatable_if_let.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,39 @@ fn main() {
103103

104104
external!({ if let 2 = $a {} });
105105
}
106+
107+
mod issue8710 {
108+
fn str_ref(cs: &[char]) {
109+
if let Some('i') = cs.iter().next() {
110+
//~^ equatable_if_let
111+
} else {
112+
todo!();
113+
}
114+
}
115+
116+
fn i32_ref(cs: &[i32]) {
117+
if let Some(1) = cs.iter().next() {
118+
//~^ equatable_if_let
119+
} else {
120+
todo!();
121+
}
122+
}
123+
124+
fn enum_ref() {
125+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
126+
enum MyEnum {
127+
A(i32),
128+
B,
129+
}
130+
131+
fn get_enum() -> Option<&'static MyEnum> {
132+
todo!()
133+
}
134+
135+
if let Some(MyEnum::B) = get_enum() {
136+
//~^ equatable_if_let
137+
} else {
138+
todo!();
139+
}
140+
}
141+
}

tests/ui/equatable_if_let.stderr

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,23 @@ error: this pattern matching can be expressed using equality
8585
LL | if let inline!("abc") = "abc" {
8686
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")`
8787

88-
error: aborting due to 14 previous errors
88+
error: this pattern matching can be expressed using `matches!`
89+
--> tests/ui/equatable_if_let.rs:109:12
90+
|
91+
LL | if let Some('i') = cs.iter().next() {
92+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some('i'))`
93+
94+
error: this pattern matching can be expressed using `matches!`
95+
--> tests/ui/equatable_if_let.rs:117:12
96+
|
97+
LL | if let Some(1) = cs.iter().next() {
98+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some(1))`
99+
100+
error: this pattern matching can be expressed using `matches!`
101+
--> tests/ui/equatable_if_let.rs:135:12
102+
|
103+
LL | if let Some(MyEnum::B) = get_enum() {
104+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(get_enum(), Some(MyEnum::B))`
105+
106+
error: aborting due to 17 previous errors
89107

0 commit comments

Comments
 (0)