| //@aux-build:proc_macros.rs | |
| #![allow(clippy::needless_ifs)] | |
| #![warn(clippy::equatable_if_let)] | |
| use proc_macros::{external, inline_macros}; | |
| use std::cmp::Ordering; | |
| #[derive(PartialEq)] | |
| enum Enum { | |
| TupleVariant(i32, u64), | |
| RecordVariant { a: i64, b: u32 }, | |
| UnitVariant, | |
| Recursive(Struct), | |
| } | |
| #[derive(PartialEq)] | |
| struct Struct { | |
| a: i32, | |
| b: bool, | |
| } | |
| struct NoPartialEqStruct { | |
| a: i32, | |
| b: bool, | |
| } | |
| enum NotPartialEq { | |
| A, | |
| B, | |
| } | |
| enum NotStructuralEq { | |
| A, | |
| B, | |
| } | |
| impl PartialEq for NotStructuralEq { | |
| fn eq(&self, _: &NotStructuralEq) -> bool { | |
| false | |
| } | |
| } | |
| fn main() { | |
| let a = 2; | |
| let b = 3; | |
| let c = Some(2); | |
| let d = Struct { a: 2, b: false }; | |
| let e = Enum::UnitVariant; | |
| let f = NotPartialEq::A; | |
| let g = NotStructuralEq::A; | |
| let h = NoPartialEqStruct { a: 2, b: false }; | |
| // true | |
| if let 2 = a {} | |
| //~^ equatable_if_let | |
| if let Ordering::Greater = a.cmp(&b) {} | |
| //~^ equatable_if_let | |
| if let Some(2) = c {} | |
| //~^ equatable_if_let | |
| if let Struct { a: 2, b: false } = d {} | |
| //~^ equatable_if_let | |
| if let Enum::TupleVariant(32, 64) = e {} | |
| //~^ equatable_if_let | |
| if let Enum::RecordVariant { a: 64, b: 32 } = e {} | |
| //~^ equatable_if_let | |
| if let Enum::UnitVariant = e {} | |
| //~^ equatable_if_let | |
| if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} | |
| //~^ equatable_if_let | |
| // false | |
| if let 2 | 3 = a {} | |
| if let x @ 2 = a {} | |
| if let Some(3 | 4) = c {} | |
| if let Struct { a, b: false } = d {} | |
| if let Struct { a: 2, b: x } = d {} | |
| if let NotPartialEq::A = f {} | |
| //~^ equatable_if_let | |
| if let NotStructuralEq::A = g {} | |
| //~^ equatable_if_let | |
| if let Some(NotPartialEq::A) = Some(f) {} | |
| //~^ equatable_if_let | |
| if let Some(NotStructuralEq::A) = Some(g) {} | |
| //~^ equatable_if_let | |
| if let NoPartialEqStruct { a: 2, b: false } = h {} | |
| //~^ equatable_if_let | |
| } | |
| mod issue8710 { | |
| fn str_ref(cs: &[char]) { | |
| if let Some('i') = cs.iter().next() { | |
| //~^ equatable_if_let | |
| } else { | |
| todo!(); | |
| } | |
| } | |
| fn i32_ref(cs: &[i32]) { | |
| if let Some(1) = cs.iter().next() { | |
| //~^ equatable_if_let | |
| } else { | |
| todo!(); | |
| } | |
| } | |
| fn enum_ref() { | |
| #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | |
| enum MyEnum { | |
| A(i32), | |
| B, | |
| } | |
| fn get_enum() -> Option<&'static MyEnum> { | |
| todo!() | |
| } | |
| if let Some(MyEnum::B) = get_enum() { | |
| //~^ equatable_if_let | |
| } else { | |
| todo!(); | |
| } | |
| } | |
| } | |
| #[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 { | |
| A, | |
| B, | |
| } | |
| impl PartialEq for NonConstEq { | |
| fn eq(&self, _other: &Self) -> bool { | |
| true | |
| } | |
| } | |
| const N: NonConstEq = NonConstEq::A; | |
| // `impl PartialEq` is not const, suggest `matches!` | |
| const _: u32 = if let NonConstEq::A = N { 0 } else { 1 }; | |
| //~^ ERROR: this pattern matching can be expressed using `matches!` | |
| const _: u32 = if let Some(NonConstEq::A) = Some(N) { 0 } else { 1 }; | |
| //~^ ERROR: this pattern matching can be expressed using `matches!` | |
| } |