blob: 2cf69cf7b2fdfd6a02b059bab7f2499d998e94b5 [file] [log] [blame] [edit]
//@aux-build:proc_macros.rs
#![allow(clippy::derive_partial_eq_without_eq, 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 a == 2 {}
//~^ equatable_if_let
if a.cmp(&b) == Ordering::Greater {}
//~^ equatable_if_let
if c == Some(2) {}
//~^ equatable_if_let
if d == (Struct { a: 2, b: false }) {}
//~^ equatable_if_let
if e == Enum::TupleVariant(32, 64) {}
//~^ equatable_if_let
if e == (Enum::RecordVariant { a: 64, b: 32 }) {}
//~^ equatable_if_let
if e == Enum::UnitVariant {}
//~^ equatable_if_let
if (e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false }) {}
//~^ 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 matches!(f, NotPartialEq::A) {}
//~^ equatable_if_let
if g == NotStructuralEq::A {}
//~^ equatable_if_let
if matches!(Some(f), Some(NotPartialEq::A)) {}
//~^ equatable_if_let
if Some(g) == Some(NotStructuralEq::A) {}
//~^ equatable_if_let
if matches!(h, NoPartialEqStruct { a: 2, b: false }) {}
//~^ equatable_if_let
}
mod issue8710 {
fn str_ref(cs: &[char]) {
if matches!(cs.iter().next(), Some('i')) {
//~^ equatable_if_let
} else {
todo!();
}
}
fn i32_ref(cs: &[i32]) {
if matches!(cs.iter().next(), Some(1)) {
//~^ 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 matches!(get_enum(), Some(MyEnum::B)) {
//~^ 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 matches!(N, NonConstEq::A) { 0 } else { 1 };
//~^ ERROR: this pattern matching can be expressed using `matches!`
const _: u32 = if matches!(Some(N), Some(NonConstEq::A)) { 0 } else { 1 };
//~^ ERROR: this pattern matching can be expressed using `matches!`
}