fix(equatable_if_let): don't lint if pattern or initializer come from expansion

This commit is contained in:
Ada Alakbarova 2025-10-26 14:36:30 +01:00
parent 2193494b6c
commit db4adbdccc
No known key found for this signature in database
4 changed files with 157 additions and 41 deletions

View file

@ -106,6 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
if let ExprKind::Let(let_expr) = expr.kind
&& is_unary_pattern(let_expr.pat)
&& !expr.span.in_external_macro(cx.sess().source_map())
&& !let_expr.pat.span.from_expansion()
&& !let_expr.init.span.from_expansion()
{
let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);

View file

@ -40,7 +40,6 @@ impl PartialEq for NotStructuralEq {
}
}
#[inline_macros]
fn main() {
let a = 2;
let b = 3;
@ -87,13 +86,6 @@ fn main() {
//~^ equatable_if_let
if matches!(h, NoPartialEqStruct { a: 2, b: false }) {}
//~^ equatable_if_let
if "abc" == inline!("abc") {
//~^ equatable_if_let
println!("OK");
}
external!({ if let 2 = $a {} });
}
mod issue8710 {
@ -132,6 +124,74 @@ mod issue8710 {
}
}
#[inline_macros]
fn issue14548() {
if let inline!("abc") = "abc" {
println!("OK");
}
let a = 2;
external!({ if let 2 = $a {} });
// Don't lint: `==`/`matches!` might be correct for a particular `$($font)|*`, but not in general
macro_rules! m1 {
($($font:pat_param)|*) => {
if let $($font)|* = "from_expansion" {}
}
}
m1!("foo");
m1!("Sans" | "Serif" | "Sans Mono");
m1!(inline!("foo"));
// Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in
// general
macro_rules! m2 {
($from_root_ctxt:pat) => {
if let $from_root_ctxt = "from_expansion" {}
};
}
m2!("foo");
m2!("Sans" | "Serif" | "Sans Mono");
m2!(inline!("foo"));
// Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in
// general
macro_rules! m3 {
($from_root_ctxt:expr) => {
if let "from_expansion" = $from_root_ctxt {}
};
}
m3!("foo");
m3!("foo");
m3!(inline!("foo"));
// Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in
// general. Don't get confused by the scrutinee coming from macro invocation
macro_rules! m4 {
($from_root_ctxt:pat) => {
if let $from_root_ctxt = inline!("from_expansion") {}
};
}
m4!("foo");
m4!("Sans" | "Serif" | "Sans Mono");
m4!(inline!("foo"));
// Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in
// general. Don't get confused by the scrutinee coming from macro invocation
macro_rules! m5 {
($from_root_ctxt:expr) => {
if let inline!("from_expansion") = $from_root_ctxt {}
};
}
m5!("foo");
m5!("foo");
m5!(inline!("foo"));
// Would be nice to lint: both sides are macro _invocations_, so the suggestion is correct in
// general
if let inline!("foo") = inline!("bar") {}
}
// PartialEq is not stable in consts yet
fn issue15376() {
enum NonConstEq {

View file

@ -40,7 +40,6 @@ impl PartialEq for NotStructuralEq {
}
}
#[inline_macros]
fn main() {
let a = 2;
let b = 3;
@ -87,13 +86,6 @@ fn main() {
//~^ equatable_if_let
if let NoPartialEqStruct { a: 2, b: false } = h {}
//~^ equatable_if_let
if let inline!("abc") = "abc" {
//~^ equatable_if_let
println!("OK");
}
external!({ if let 2 = $a {} });
}
mod issue8710 {
@ -132,6 +124,74 @@ mod issue8710 {
}
}
#[inline_macros]
fn issue14548() {
if let inline!("abc") = "abc" {
println!("OK");
}
let a = 2;
external!({ if let 2 = $a {} });
// Don't lint: `==`/`matches!` might be correct for a particular `$($font)|*`, but not in general
macro_rules! m1 {
($($font:pat_param)|*) => {
if let $($font)|* = "from_expansion" {}
}
}
m1!("foo");
m1!("Sans" | "Serif" | "Sans Mono");
m1!(inline!("foo"));
// Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in
// general
macro_rules! m2 {
($from_root_ctxt:pat) => {
if let $from_root_ctxt = "from_expansion" {}
};
}
m2!("foo");
m2!("Sans" | "Serif" | "Sans Mono");
m2!(inline!("foo"));
// Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in
// general
macro_rules! m3 {
($from_root_ctxt:expr) => {
if let "from_expansion" = $from_root_ctxt {}
};
}
m3!("foo");
m3!("foo");
m3!(inline!("foo"));
// Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in
// general. Don't get confused by the scrutinee coming from macro invocation
macro_rules! m4 {
($from_root_ctxt:pat) => {
if let $from_root_ctxt = inline!("from_expansion") {}
};
}
m4!("foo");
m4!("Sans" | "Serif" | "Sans Mono");
m4!(inline!("foo"));
// Don't lint: the suggestion might be correct for a particular `$from_root_ctxt`, but not in
// general. Don't get confused by the scrutinee coming from macro invocation
macro_rules! m5 {
($from_root_ctxt:expr) => {
if let inline!("from_expansion") = $from_root_ctxt {}
};
}
m5!("foo");
m5!("foo");
m5!(inline!("foo"));
// Would be nice to lint: both sides are macro _invocations_, so the suggestion is correct in
// general
if let inline!("foo") = inline!("bar") {}
}
// PartialEq is not stable in consts yet
fn issue15376() {
enum NonConstEq {

View file

@ -1,5 +1,5 @@
error: this pattern matching can be expressed using equality
--> tests/ui/equatable_if_let.rs:56:8
--> tests/ui/equatable_if_let.rs:55:8
|
LL | if let 2 = a {}
| ^^^^^^^^^ help: try: `a == 2`
@ -8,112 +8,106 @@ LL | if let 2 = a {}
= help: to override `-D warnings` add `#[allow(clippy::equatable_if_let)]`
error: this pattern matching can be expressed using equality
--> tests/ui/equatable_if_let.rs:58:8
--> tests/ui/equatable_if_let.rs:57:8
|
LL | if let Ordering::Greater = a.cmp(&b) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater`
error: this pattern matching can be expressed using equality
--> tests/ui/equatable_if_let.rs:60:8
--> tests/ui/equatable_if_let.rs:59:8
|
LL | if let Some(2) = c {}
| ^^^^^^^^^^^^^^^ help: try: `c == Some(2)`
error: this pattern matching can be expressed using equality
--> tests/ui/equatable_if_let.rs:62:8
--> tests/ui/equatable_if_let.rs:61:8
|
LL | if let Struct { a: 2, b: false } = d {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })`
error: this pattern matching can be expressed using equality
--> tests/ui/equatable_if_let.rs:64:8
--> tests/ui/equatable_if_let.rs:63:8
|
LL | if let Enum::TupleVariant(32, 64) = e {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)`
error: this pattern matching can be expressed using equality
--> tests/ui/equatable_if_let.rs:66:8
--> tests/ui/equatable_if_let.rs:65:8
|
LL | if let Enum::RecordVariant { a: 64, b: 32 } = e {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })`
error: this pattern matching can be expressed using equality
--> tests/ui/equatable_if_let.rs:68:8
--> tests/ui/equatable_if_let.rs:67:8
|
LL | if let Enum::UnitVariant = e {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant`
error: this pattern matching can be expressed using equality
--> tests/ui/equatable_if_let.rs:70:8
--> tests/ui/equatable_if_let.rs:69:8
|
LL | if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })`
error: this pattern matching can be expressed using `matches!`
--> tests/ui/equatable_if_let.rs:80:8
--> tests/ui/equatable_if_let.rs:79:8
|
LL | if let NotPartialEq::A = f {}
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(f, NotPartialEq::A)`
error: this pattern matching can be expressed using equality
--> tests/ui/equatable_if_let.rs:82:8
--> tests/ui/equatable_if_let.rs:81:8
|
LL | if let NotStructuralEq::A = g {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A`
error: this pattern matching can be expressed using `matches!`
--> tests/ui/equatable_if_let.rs:84:8
--> tests/ui/equatable_if_let.rs:83:8
|
LL | if let Some(NotPartialEq::A) = Some(f) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(f), Some(NotPartialEq::A))`
error: this pattern matching can be expressed using equality
--> tests/ui/equatable_if_let.rs:86:8
--> tests/ui/equatable_if_let.rs:85:8
|
LL | if let Some(NotStructuralEq::A) = Some(g) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)`
error: this pattern matching can be expressed using `matches!`
--> tests/ui/equatable_if_let.rs:88:8
--> tests/ui/equatable_if_let.rs:87:8
|
LL | if let NoPartialEqStruct { a: 2, b: false } = h {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(h, NoPartialEqStruct { a: 2, b: false })`
error: this pattern matching can be expressed using equality
--> tests/ui/equatable_if_let.rs:91:8
|
LL | if let inline!("abc") = "abc" {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")`
error: this pattern matching can be expressed using `matches!`
--> tests/ui/equatable_if_let.rs:101:12
--> tests/ui/equatable_if_let.rs:93:12
|
LL | if let Some('i') = cs.iter().next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some('i'))`
error: this pattern matching can be expressed using `matches!`
--> tests/ui/equatable_if_let.rs:109:12
--> tests/ui/equatable_if_let.rs:101:12
|
LL | if let Some(1) = cs.iter().next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some(1))`
error: this pattern matching can be expressed using `matches!`
--> tests/ui/equatable_if_let.rs:127:12
--> tests/ui/equatable_if_let.rs:119:12
|
LL | if let Some(MyEnum::B) = get_enum() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(get_enum(), Some(MyEnum::B))`
error: this pattern matching can be expressed using `matches!`
--> tests/ui/equatable_if_let.rs:158:23
--> tests/ui/equatable_if_let.rs:210:23
|
LL | const _: u32 = if let NonConstEq::A = N { 0 } else { 1 };
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(N, NonConstEq::A)`
error: this pattern matching can be expressed using `matches!`
--> tests/ui/equatable_if_let.rs:160:23
--> tests/ui/equatable_if_let.rs:212:23
|
LL | const _: u32 = if let Some(NonConstEq::A) = Some(N) { 0 } else { 1 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(N), Some(NonConstEq::A))`
error: aborting due to 19 previous errors
error: aborting due to 18 previous errors