From 77c21231476887b03175e69740a1f06b43441d39 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 10 Oct 2025 09:40:38 +0000 Subject: [PATCH 1/3] Better docs for PartialEq --- library/core/src/cmp.rs | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 95896ab144187..3a24956a292d0 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -249,14 +249,23 @@ use crate::ops::ControlFlow; #[rustc_diagnostic_item = "PartialEq"] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] pub const trait PartialEq: PointeeSized { - /// Tests for `self` and `other` values to be equal, and is used by `==`. + /// Equality operator `==`. + /// + /// Implementation of the "is equal to" operator `==`: + /// tests whether its arguments are equal. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "cmp_partialeq_eq"] fn eq(&self, other: &Rhs) -> bool; - /// Tests for `!=`. The default implementation is almost always sufficient, - /// and should not be overridden without very good reason. + /// Inequality operator `!=`. + /// + /// Implementation of the "is not equal to" or "is different from" operator `!=`: + /// tests whether its arguments are different. + /// + /// # Default implementation + /// The default implementation of the inequality operator simply calls + /// the implementation of the equality operator and negates the result. #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -1854,19 +1863,31 @@ mod impls { use crate::marker::PointeeSized; use crate::ops::ControlFlow::{self, Break, Continue}; - macro_rules! partial_eq_impl { + /// Implements `PartialEq` for primitive types. + /// + /// Primitive types have a compiler-defined primitive implementation of `==` and `!=`. + /// This implements the `PartialEq` trait is terms of those primitive implementations. + /// + /// NOTE: Calling this on a non-primitive type (such as `()`) + /// leads to infinitely recursive implementations. + macro_rules! impl_partial_eq_for_primitive { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] impl const PartialEq for $t { #[inline] fn eq(&self, other: &Self) -> bool { *self == *other } + // Override the default to use the primitive implementation for `!=`. #[inline] fn ne(&self, other: &Self) -> bool { *self != *other } } )*) } + impl_partial_eq_for_primitive! { + bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 + } + #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] impl const PartialEq for () { @@ -1880,10 +1901,6 @@ mod impls { } } - partial_eq_impl! { - bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 - } - macro_rules! eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] From a95a0d3bf1a8f116902df52bc3f067b316d09f44 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 4 Jul 2025 09:35:29 +0000 Subject: [PATCH 2/3] reduce repetition with macros --- library/core/src/cmp.rs | 262 ++++++++++++++-------------------------- 1 file changed, 89 insertions(+), 173 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 3a24956a292d0..652b43dfe0e01 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -2092,185 +2092,101 @@ mod impls { } } - // & pointers + // reference types - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] - impl const PartialEq<&B> for &A - where - A: [const] PartialEq, - { - #[inline] - fn eq(&self, other: &&B) -> bool { - PartialEq::eq(*self, *other) - } - #[inline] - fn ne(&self, other: &&B) -> bool { - PartialEq::ne(*self, *other) - } - } - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] - impl const PartialOrd<&B> for &A - where - A: [const] PartialOrd, - { - #[inline] - fn partial_cmp(&self, other: &&B) -> Option { - PartialOrd::partial_cmp(*self, *other) - } - #[inline] - fn lt(&self, other: &&B) -> bool { - PartialOrd::lt(*self, *other) - } - #[inline] - fn le(&self, other: &&B) -> bool { - PartialOrd::le(*self, *other) - } - #[inline] - fn gt(&self, other: &&B) -> bool { - PartialOrd::gt(*self, *other) - } - #[inline] - fn ge(&self, other: &&B) -> bool { - PartialOrd::ge(*self, *other) - } - #[inline] - fn __chaining_lt(&self, other: &&B) -> ControlFlow { - PartialOrd::__chaining_lt(*self, *other) - } - #[inline] - fn __chaining_le(&self, other: &&B) -> ControlFlow { - PartialOrd::__chaining_le(*self, *other) - } - #[inline] - fn __chaining_gt(&self, other: &&B) -> ControlFlow { - PartialOrd::__chaining_gt(*self, *other) - } - #[inline] - fn __chaining_ge(&self, other: &&B) -> ControlFlow { - PartialOrd::__chaining_ge(*self, *other) - } - } - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] - impl const Ord for &A - where - A: [const] Ord, - { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - Ord::cmp(*self, *other) - } + macro_rules! impl_partial_eq { + (<$A:ident, $B:ident> for $(($ref_A:ty, $ref_B:ty))*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<$A, $B> const PartialEq<$ref_B> for $ref_A + where + $A: [const] PartialEq<$B> + PointeeSized, + $B: PointeeSized, + { + #[inline] + fn eq(&self, other: &$ref_B) -> bool { + PartialEq::eq(*self, *other) + } + // if >::ne uses inline assembly or FFI, then + // this forwarding impl may be more efficient than the default impl + #[inline] + fn ne(&self, other: &$ref_B) -> bool { + PartialEq::ne(*self, *other) + } + } + )*) } - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] - impl const Eq for &A where A: [const] Eq {} - // &mut pointers + impl_partial_eq!( for (&A, &B) (&A, &mut B) (&mut A, &B) (&mut A, &mut B)); - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] - impl const PartialEq<&mut B> for &mut A - where - A: [const] PartialEq, - { - #[inline] - fn eq(&self, other: &&mut B) -> bool { - PartialEq::eq(*self, *other) - } - #[inline] - fn ne(&self, other: &&mut B) -> bool { - PartialEq::ne(*self, *other) - } - } - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] - impl const PartialOrd<&mut B> for &mut A - where - A: [const] PartialOrd, - { - #[inline] - fn partial_cmp(&self, other: &&mut B) -> Option { - PartialOrd::partial_cmp(*self, *other) - } - #[inline] - fn lt(&self, other: &&mut B) -> bool { - PartialOrd::lt(*self, *other) - } - #[inline] - fn le(&self, other: &&mut B) -> bool { - PartialOrd::le(*self, *other) - } - #[inline] - fn gt(&self, other: &&mut B) -> bool { - PartialOrd::gt(*self, *other) - } - #[inline] - fn ge(&self, other: &&mut B) -> bool { - PartialOrd::ge(*self, *other) - } - #[inline] - fn __chaining_lt(&self, other: &&mut B) -> ControlFlow { - PartialOrd::__chaining_lt(*self, *other) - } - #[inline] - fn __chaining_le(&self, other: &&mut B) -> ControlFlow { - PartialOrd::__chaining_le(*self, *other) - } - #[inline] - fn __chaining_gt(&self, other: &&mut B) -> ControlFlow { - PartialOrd::__chaining_gt(*self, *other) - } - #[inline] - fn __chaining_ge(&self, other: &&mut B) -> ControlFlow { - PartialOrd::__chaining_ge(*self, *other) - } - } - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] - impl const Ord for &mut A - where - A: [const] Ord, - { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - Ord::cmp(*self, *other) - } + macro_rules! impl_partial_ord { + (<$A:ident, $B:ident> for $(($ref_A:ty, $ref_B:ty))*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<$A, $B> const PartialOrd<$ref_B> for $ref_A + where + $A: [const] PartialOrd<$B> + PointeeSized, + $B: PointeeSized, + { + #[inline] + fn partial_cmp(&self, other: &$ref_B) -> Option { + PartialOrd::partial_cmp(*self, *other) + } + #[inline] + fn lt(&self, other: &$ref_B) -> bool { + PartialOrd::lt(*self, *other) + } + #[inline] + fn le(&self, other: &$ref_B) -> bool { + PartialOrd::le(*self, *other) + } + #[inline] + fn gt(&self, other: &$ref_B) -> bool { + PartialOrd::gt(*self, *other) + } + #[inline] + fn ge(&self, other: &$ref_B) -> bool { + PartialOrd::ge(*self, *other) + } + #[inline] + fn __chaining_lt(&self, other: &$ref_B) -> ControlFlow { + PartialOrd::__chaining_lt(*self, *other) + } + #[inline] + fn __chaining_le(&self, other: &$ref_B) -> ControlFlow { + PartialOrd::__chaining_le(*self, *other) + } + #[inline] + fn __chaining_gt(&self, other: &$ref_B) -> ControlFlow { + PartialOrd::__chaining_gt(*self, *other) + } + #[inline] + fn __chaining_ge(&self, other: &$ref_B) -> ControlFlow { + PartialOrd::__chaining_ge(*self, *other) + } + } + )*) } - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] - impl const Eq for &mut A where A: [const] Eq {} - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] - impl const PartialEq<&mut B> for &A - where - A: [const] PartialEq, - { - #[inline] - fn eq(&self, other: &&mut B) -> bool { - PartialEq::eq(*self, *other) - } - #[inline] - fn ne(&self, other: &&mut B) -> bool { - PartialEq::ne(*self, *other) - } - } + impl_partial_ord!( for (&A, &B) /*(&A, &mut B) (&mut A, &B)*/ (&mut A, &mut B)); - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] - impl const PartialEq<&B> for &mut A - where - A: [const] PartialEq, - { - #[inline] - fn eq(&self, other: &&B) -> bool { - PartialEq::eq(*self, *other) - } - #[inline] - fn ne(&self, other: &&B) -> bool { - PartialEq::ne(*self, *other) - } + macro_rules! impl_ord_eq { + (<$A:ident> for $($ref_A:ty),*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<$A: [const] Ord + PointeeSized> const Ord for $ref_A + { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + Ord::cmp(*self, *other) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<$A: [const] Eq + PointeeSized> const Eq for $ref_A {} + )*) } + + impl_ord_eq!( for &A, &mut A); } From 6912f1516a86d592363053a2472f539224bb21b7 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 3 Jul 2025 17:42:16 +0000 Subject: [PATCH 3/3] clippy fix: remove manual PartialEq::()::ne implementation --- library/core/src/cmp.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 652b43dfe0e01..bf395b0664600 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1895,10 +1895,6 @@ mod impls { fn eq(&self, _other: &()) -> bool { true } - #[inline] - fn ne(&self, _other: &()) -> bool { - false - } } macro_rules! eq_impl {