From 05a818c204753b76b8f6b4e57d70ed5be8588c08 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 ++++++++++++++----- .../self-referential-2.current.stderr | 2 +- .../self-referential-3.stderr | 2 +- .../self-referential-4.stderr | 6 ++-- .../self-referential.stderr | 6 ++-- 5 files changed, 33 insertions(+), 16 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index feb9c43196044..a0bb082634695 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")] @@ -1857,19 +1866,31 @@ mod impls { use crate::ops::ControlFlow::{self, Break, Continue}; use crate::panic::const_assert; - 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 () { @@ -1883,10 +1904,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")] diff --git a/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr b/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr index ca26e3dd03f35..f656a274703ee 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr @@ -12,7 +12,7 @@ help: the trait `PartialEq` is not implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/self-referential-3.stderr b/tests/ui/type-alias-impl-trait/self-referential-3.stderr index 8592de243adac..7bc4c6def624d 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-3.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential-3.stderr @@ -13,7 +13,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/self-referential-4.stderr b/tests/ui/type-alias-impl-trait/self-referential-4.stderr index c6bf1973fcbb1..76c5611906d34 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-4.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential-4.stderr @@ -12,7 +12,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `Foo<'static, 'b>` --> $DIR/self-referential-4.rs:13:31 @@ -28,7 +28,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `Moo<'static, 'a>` --> $DIR/self-referential-4.rs:20:31 @@ -44,7 +44,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/type-alias-impl-trait/self-referential.stderr b/tests/ui/type-alias-impl-trait/self-referential.stderr index 7b4e6e9cac528..62d85466cde1a 100644 --- a/tests/ui/type-alias-impl-trait/self-referential.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential.stderr @@ -13,7 +13,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)` --> $DIR/self-referential.rs:14:31 @@ -30,7 +30,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)` --> $DIR/self-referential.rs:22:31 @@ -47,7 +47,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors From 288553ef2e7679f212e30a0ca3c77746b5921313 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 a0bb082634695..dec1e6e5e91c5 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -2115,185 +2115,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 6be8deb51b3fcdbc9743694c64e8cf054b8ae0c2 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 dec1e6e5e91c5..1a51c35f1115e 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1898,10 +1898,6 @@ mod impls { fn eq(&self, _other: &()) -> bool { true } - #[inline] - fn ne(&self, _other: &()) -> bool { - false - } } macro_rules! eq_impl {