Skip to content

Commit ad69347

Browse files
committed
fix: equatable_if_let suggests wrongly when involving reference
1 parent 91ed606 commit ad69347

File tree

4 files changed

+124
-2
lines changed

4 files changed

+124
-2
lines changed

clippy_lints/src/equatable_if_let.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,38 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T
6868
}
6969
}
7070

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

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

tests/ui/equatable_if_let.fixed

+36
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

+36
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

+19-1
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)