diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index c3fc09343dbf..d872d5628b2c 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_in_const_context; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; @@ -110,7 +111,16 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { let pat_ty = cx.typeck_results().pat_ty(let_expr.pat); let mut applicability = Applicability::MachineApplicable; - if is_structural_partial_eq(cx, exp_ty, pat_ty) && !contains_type_mismatch(cx, let_expr.pat) { + if is_structural_partial_eq(cx, exp_ty, pat_ty) + && !contains_type_mismatch(cx, let_expr.pat) + // Calls to trait methods (`PartialEq::eq` in this case) aren't stable yet. We could _technically_ + // try looking at whether: + // 1) features `const_trait_impl` and `const_cmp` are enabled + // 2) implementation of `PartialEq for ExpTy` has `fn eq` that is `const` + // + // but that didn't quite work out (see #15482), so we just reject outright in this case + && !is_in_const_context(cx) + { let pat_str = match let_expr.pat.kind { PatKind::Struct(..) => format!( "({})", diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed index 58fbad64a78d..867ba1904bda 100644 --- a/tests/ui/equatable_if_let.fixed +++ b/tests/ui/equatable_if_let.fixed @@ -139,3 +139,24 @@ mod issue8710 { } } } + +// 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!` +} diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs index cca97c76b509..6690ca24339d 100644 --- a/tests/ui/equatable_if_let.rs +++ b/tests/ui/equatable_if_let.rs @@ -139,3 +139,24 @@ mod issue8710 { } } } + +// 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!` +} diff --git a/tests/ui/equatable_if_let.stderr b/tests/ui/equatable_if_let.stderr index dd1832ad68b2..75242e1c527e 100644 --- a/tests/ui/equatable_if_let.stderr +++ b/tests/ui/equatable_if_let.stderr @@ -103,5 +103,17 @@ error: this pattern matching can be expressed using `matches!` LL | if let Some(MyEnum::B) = get_enum() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(get_enum(), Some(MyEnum::B))` -error: aborting due to 17 previous errors +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:158: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 + | +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 diff --git a/tests/ui/equatable_if_let_const_cmp.fixed b/tests/ui/equatable_if_let_const_cmp.fixed new file mode 100644 index 000000000000..51dab25ed6d8 --- /dev/null +++ b/tests/ui/equatable_if_let_const_cmp.fixed @@ -0,0 +1,24 @@ +#![warn(clippy::equatable_if_let)] +#![allow(clippy::eq_op)] +#![feature(const_trait_impl, const_cmp)] + +fn issue15376() { + enum ConstEq { + A, + B, + } + impl const PartialEq for ConstEq { + fn eq(&self, _other: &Self) -> bool { + true + } + } + + const C: ConstEq = ConstEq::A; + + // `impl PartialEq` is const... but we still suggest `matches!` for now + // TODO: detect this and suggest `=` + const _: u32 = if matches!(C, ConstEq::A) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` + const _: u32 = if matches!(Some(C), Some(ConstEq::A)) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` +} diff --git a/tests/ui/equatable_if_let_const_cmp.rs b/tests/ui/equatable_if_let_const_cmp.rs new file mode 100644 index 000000000000..b402e05c53de --- /dev/null +++ b/tests/ui/equatable_if_let_const_cmp.rs @@ -0,0 +1,24 @@ +#![warn(clippy::equatable_if_let)] +#![allow(clippy::eq_op)] +#![feature(const_trait_impl, const_cmp)] + +fn issue15376() { + enum ConstEq { + A, + B, + } + impl const PartialEq for ConstEq { + fn eq(&self, _other: &Self) -> bool { + true + } + } + + const C: ConstEq = ConstEq::A; + + // `impl PartialEq` is const... but we still suggest `matches!` for now + // TODO: detect this and suggest `=` + const _: u32 = if let ConstEq::A = C { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` + const _: u32 = if let Some(ConstEq::A) = Some(C) { 0 } else { 1 }; + //~^ ERROR: this pattern matching can be expressed using `matches!` +} diff --git a/tests/ui/equatable_if_let_const_cmp.stderr b/tests/ui/equatable_if_let_const_cmp.stderr new file mode 100644 index 000000000000..ec72e42d6430 --- /dev/null +++ b/tests/ui/equatable_if_let_const_cmp.stderr @@ -0,0 +1,17 @@ +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let_const_cmp.rs:20:23 + | +LL | const _: u32 = if let ConstEq::A = C { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^ help: try: `matches!(C, ConstEq::A)` + | + = note: `-D clippy::equatable-if-let` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::equatable_if_let)]` + +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let_const_cmp.rs:22:23 + | +LL | const _: u32 = if let Some(ConstEq::A) = Some(C) { 0 } else { 1 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(C), Some(ConstEq::A))` + +error: aborting due to 2 previous errors +