fix equatable_if_let: FP in const context

This commit is contained in:
Ada Alakbarova 2025-08-13 21:16:29 +02:00
parent c48592eb49
commit 757bad7206
No known key found for this signature in database
7 changed files with 131 additions and 2 deletions

View file

@ -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<Rhs=PatTy> 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!(
"({})",

View file

@ -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!`
}

View file

@ -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!`
}

View file

@ -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

View file

@ -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!`
}

View file

@ -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!`
}

View file

@ -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