Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion clippy_lints/src/equatable_if_let.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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!(
"({})",
Expand Down
21 changes: 21 additions & 0 deletions tests/ui/equatable_if_let.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -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!`
}
21 changes: 21 additions & 0 deletions tests/ui/equatable_if_let.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!`
}
14 changes: 13 additions & 1 deletion tests/ui/equatable_if_let.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

24 changes: 24 additions & 0 deletions tests/ui/equatable_if_let_const_cmp.fixed
Original file line number Diff line number Diff line change
@@ -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!`
}
24 changes: 24 additions & 0 deletions tests/ui/equatable_if_let_const_cmp.rs
Original file line number Diff line number Diff line change
@@ -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!`
}
17 changes: 17 additions & 0 deletions tests/ui/equatable_if_let_const_cmp.stderr
Original file line number Diff line number Diff line change
@@ -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