Skip to content

Commit 7d38cba

Browse files
committed
make sure they have the same type
1 parent 90b0409 commit 7d38cba

File tree

3 files changed

+106
-57
lines changed

3 files changed

+106
-57
lines changed

clippy_lints/src/matches/redundant_guard.rs

Lines changed: 34 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,9 @@ pub(super) fn check(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
4747
arm.guard,
4848
&mut app,
4949
);
50-
51-
continue;
5250
}
53-
5451
// `Some(x) if let Some(2) = x`
55-
if let Guard::IfLet(let_expr) = guard
52+
else if let Guard::IfLet(let_expr) = guard
5653
&& let pat = let_expr.pat
5754
&& let Some((pat_binding, field_name)) = get_pat_binding(cx, let_expr.init, outer_arm)
5855
{
@@ -66,16 +63,20 @@ pub(super) fn check(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
6663
None,
6764
&mut app,
6865
);
69-
70-
continue;
7166
}
72-
7367
// `Some(x) if x == Some(2)`
74-
if let Guard::If(if_expr) = guard
68+
else if let Guard::If(if_expr) = guard
7569
&& let ExprKind::Binary(bin_op, local, pat) = if_expr.kind
7670
&& matches!(bin_op.node, BinOpKind::Eq)
7771
&& let Some((pat_binding, field_name)) = get_pat_binding(cx, local, outer_arm)
7872
&& expr_can_be_pat(cx, pat)
73+
// Ensure they have the same type. If they don't, we'd need deref coercion which isn't
74+
// possible (currently) in a pattern. In some cases, you can use something like
75+
// `as_deref` or similar but in general, we shouldn't lint this as it'd create an
76+
// extraordinary amount of FPs.
77+
//
78+
// This isn't necessary in the other two checks, as they must be a pattern already.
79+
&& cx.typeck_results().expr_ty(local) == cx.typeck_results().expr_ty(pat)
7980
{
8081
emit_redundant_guard(
8182
cx,
@@ -87,8 +88,6 @@ pub(super) fn check(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
8788
None,
8889
&mut app,
8990
);
90-
91-
continue;
9291
}
9392
}
9493
}
@@ -198,52 +197,30 @@ fn emit_redundant_guard(
198197

199198
/// Checks if the given `Expr` can also be represented as a `Pat`.
200199
fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
201-
fn helper(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
202-
for_each_expr(expr, |expr| {
203-
let expr = expr.peel_blocks();
204-
if match expr.kind {
205-
ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat,
206-
ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => {
207-
// Allow ctors
208-
matches!(cx.qpath_res(&qpath, c.hir_id), Res::Def(DefKind::Ctor(..), ..))
209-
},
210-
ExprKind::AddrOf(.., expr) => helper(cx, expr),
211-
ExprKind::Array(exprs) | ExprKind::Tup(exprs) => {
212-
for expr in exprs {
213-
if !helper(cx, expr) {
214-
return ControlFlow::Break(());
215-
}
216-
}
217-
218-
true
219-
},
220-
ExprKind::Struct(_, fields, rest) => {
221-
for field in fields {
222-
if !helper(cx, field.expr) {
223-
return ControlFlow::Break(());
224-
}
225-
}
226-
227-
if rest.is_some() {
228-
return ControlFlow::Break(());
229-
}
230-
231-
true
232-
},
233-
ExprKind::Path(qpath) => {
234-
// Can't compare a local with another local in a pat
235-
!matches!(cx.qpath_res(&qpath, expr.hir_id), Res::Local(..))
236-
},
237-
ExprKind::Lit(..) => true,
238-
_ => false,
239-
} {
240-
return ControlFlow::Continue(());
241-
}
242-
243-
ControlFlow::Break(())
244-
})
245-
.is_none()
246-
}
200+
for_each_expr(expr, |expr| {
201+
if match expr.kind {
202+
ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat,
203+
ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => {
204+
// Allow ctors
205+
matches!(cx.qpath_res(&qpath, c.hir_id), Res::Def(DefKind::Ctor(..), ..))
206+
},
207+
ExprKind::Path(qpath) => {
208+
matches!(
209+
cx.qpath_res(&qpath, expr.hir_id),
210+
Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Ctor(..), ..),
211+
)
212+
},
213+
ExprKind::AddrOf(..)
214+
| ExprKind::Array(..)
215+
| ExprKind::Tup(..)
216+
| ExprKind::Struct(..)
217+
| ExprKind::Lit(..) => true,
218+
_ => false,
219+
} {
220+
return ControlFlow::Continue(());
221+
}
247222

248-
helper(cx, expr)
223+
ControlFlow::Break(())
224+
})
225+
.is_none()
249226
}

tests/ui/redundant_guard.fixed

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ fn main() {
5656
B { e: Some(A(2)) } => ..,
5757
_ => todo!(),
5858
};
59+
// Do not lint, since we cannot represent this as a pattern (at least, without a conversion)
60+
let v = Some(vec![1u8, 2, 3]);
61+
match v {
62+
Some(x) if x == [1] => {},
63+
_ => {},
64+
}
5965

6066
external! {
6167
let x = Some(Some(1));
@@ -73,3 +79,33 @@ fn main() {
7379
};
7480
}
7581
}
82+
83+
// Do not lint
84+
85+
fn f(s: Option<std::ffi::OsString>) {
86+
match s {
87+
Some(x) if x == "a" => {},
88+
_ => {},
89+
}
90+
}
91+
92+
struct S {
93+
a: usize,
94+
}
95+
96+
impl PartialEq for S {
97+
fn eq(&self, _: &Self) -> bool {
98+
true
99+
}
100+
}
101+
102+
impl Eq for S {}
103+
104+
static CONST_S: S = S { a: 1 };
105+
106+
fn g(opt_s: Option<S>) {
107+
match opt_s {
108+
Some(x) if x == CONST_S => {},
109+
_ => {},
110+
}
111+
}

tests/ui/redundant_guard.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ fn main() {
5656
B { e } if matches!(e, Some(A(2))) => ..,
5757
_ => todo!(),
5858
};
59+
// Do not lint, since we cannot represent this as a pattern (at least, without a conversion)
60+
let v = Some(vec![1u8, 2, 3]);
61+
match v {
62+
Some(x) if x == [1] => {},
63+
_ => {},
64+
}
5965

6066
external! {
6167
let x = Some(Some(1));
@@ -73,3 +79,33 @@ fn main() {
7379
};
7480
}
7581
}
82+
83+
// Do not lint
84+
85+
fn f(s: Option<std::ffi::OsString>) {
86+
match s {
87+
Some(x) if x == "a" => {},
88+
_ => {},
89+
}
90+
}
91+
92+
struct S {
93+
a: usize,
94+
}
95+
96+
impl PartialEq for S {
97+
fn eq(&self, _: &Self) -> bool {
98+
true
99+
}
100+
}
101+
102+
impl Eq for S {}
103+
104+
static CONST_S: S = S { a: 1 };
105+
106+
fn g(opt_s: Option<S>) {
107+
match opt_s {
108+
Some(x) if x == CONST_S => {},
109+
_ => {},
110+
}
111+
}

0 commit comments

Comments
 (0)