From 40336d7c863fd8775f67fd39da4e498e47f9be7a Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Mon, 25 Nov 2024 20:53:35 +0100 Subject: [PATCH] switch deprecated implicit eq for simple enums --- newsfragments/4730.removed.md | 1 + pyo3-macros-backend/src/pyclass.rs | 17 +---- pyo3-macros-backend/src/pymethod.rs | 9 --- src/impl_/pyclass.rs | 46 ------------- tests/test_enum.rs | 85 ++++++++----------------- tests/ui/deprecations.rs | 6 -- tests/ui/deprecations.stderr | 8 --- tests/ui/invalid_proto_pymethods.stderr | 11 ---- tests/ui/invalid_pyclass_args.stderr | 11 ---- 9 files changed, 27 insertions(+), 167 deletions(-) create mode 100644 newsfragments/4730.removed.md diff --git a/newsfragments/4730.removed.md b/newsfragments/4730.removed.md new file mode 100644 index 00000000000..de8b64f9ba6 --- /dev/null +++ b/newsfragments/4730.removed.md @@ -0,0 +1 @@ +Removed the deprecated implicit eq fallback for simple enums. \ No newline at end of file diff --git a/pyo3-macros-backend/src/pyclass.rs b/pyo3-macros-backend/src/pyclass.rs index 93596611f18..16e3c58f6ad 100644 --- a/pyo3-macros-backend/src/pyclass.rs +++ b/pyo3-macros-backend/src/pyclass.rs @@ -1903,24 +1903,11 @@ fn pyclass_richcmp_simple_enum( ensure_spanned!(options.eq.is_some(), eq_int.span() => "The `eq_int` option requires the `eq` option."); } - let deprecation = (options.eq_int.is_none() && options.eq.is_none()) - .then(|| { - quote! { - let _ = #pyo3_path::impl_::pyclass::DeprecationTest::<#cls>::new().autogenerated_equality(); - } - }) - .unwrap_or_default(); - - let mut options = options.clone(); - if options.eq.is_none() { - options.eq_int = Some(parse_quote!(eq_int)); - } - if options.eq.is_none() && options.eq_int.is_none() { return Ok((None, None)); } - let arms = pyclass_richcmp_arms(&options, ctx)?; + let arms = pyclass_richcmp_arms(options, ctx)?; let eq = options.eq.map(|eq| { quote_spanned! { eq.span() => @@ -1954,8 +1941,6 @@ fn pyclass_richcmp_simple_enum( other: &#pyo3_path::Bound<'_, #pyo3_path::PyAny>, op: #pyo3_path::pyclass::CompareOp ) -> #pyo3_path::PyResult<#pyo3_path::PyObject> { - #deprecation - #eq #eq_int diff --git a/pyo3-macros-backend/src/pymethod.rs b/pyo3-macros-backend/src/pymethod.rs index 560c3c9dcc1..1254a8d510b 100644 --- a/pyo3-macros-backend/src/pymethod.rs +++ b/pyo3-macros-backend/src/pymethod.rs @@ -1348,14 +1348,6 @@ impl SlotDef { )?; let name = spec.name; let holders = holders.init_holders(ctx); - let dep = if method_name == "__richcmp__" { - quote! { - #[allow(unknown_lints, non_local_definitions)] - impl #pyo3_path::impl_::pyclass::HasCustomRichCmp for #cls {} - } - } else { - TokenStream::default() - }; let associated_method = quote! { #[allow(non_snake_case)] unsafe fn #wrapper_ident( @@ -1363,7 +1355,6 @@ impl SlotDef { _raw_slf: *mut #pyo3_path::ffi::PyObject, #(#arg_idents: #arg_types),* ) -> #pyo3_path::PyResult<#ret_ty> { - #dep let function = #cls::#name; // Shadow the method name to avoid #3017 let _slf = _raw_slf; #holders diff --git a/src/impl_/pyclass.rs b/src/impl_/pyclass.rs index 7bb61442ec5..ac5c6e3e3f0 100644 --- a/src/impl_/pyclass.rs +++ b/src/impl_/pyclass.rs @@ -878,8 +878,6 @@ macro_rules! generate_pyclass_richcompare_slot { other: *mut $crate::ffi::PyObject, op: ::std::os::raw::c_int, ) -> *mut $crate::ffi::PyObject { - impl $crate::impl_::pyclass::HasCustomRichCmp for $cls {} - $crate::impl_::trampoline::richcmpfunc(slf, other, op, |py, slf, other, op| { use $crate::class::basic::CompareOp; use $crate::impl_::pyclass::*; @@ -1546,50 +1544,6 @@ impl ConvertField(Deprecation, ::std::marker::PhantomData); -pub struct Deprecation; - -impl DeprecationTest { - #[inline] - #[allow(clippy::new_without_default)] - pub const fn new() -> Self { - DeprecationTest(Deprecation, ::std::marker::PhantomData) - } -} - -impl std::ops::Deref for DeprecationTest { - type Target = Deprecation; - #[inline] - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DeprecationTest -where - T: HasCustomRichCmp, -{ - /// For `HasCustomRichCmp` types; no deprecation warning. - #[inline] - pub fn autogenerated_equality(&self) {} -} - -impl Deprecation { - #[deprecated( - since = "0.22.0", - note = "Implicit equality for simple enums is deprecated. Use `#[pyclass(eq, eq_int)]` to keep the current behavior." - )] - /// For types which don't implement `HasCustomRichCmp`; emits deprecation warning. - #[inline] - pub fn autogenerated_equality(&self) {} -} - #[cfg(test)] #[cfg(feature = "macros")] mod tests { diff --git a/tests/test_enum.rs b/tests/test_enum.rs index 40c5f4681a8..537f8281297 100644 --- a/tests/test_enum.rs +++ b/tests/test_enum.rs @@ -23,6 +23,27 @@ fn test_enum_class_attr() { }) } +#[test] +fn test_enum_eq_enum() { + Python::with_gil(|py| { + let var1 = Py::new(py, MyEnum::Variant).unwrap(); + let var2 = Py::new(py, MyEnum::Variant).unwrap(); + let other_var = Py::new(py, MyEnum::OtherVariant).unwrap(); + py_assert!(py, var1 var2, "var1 == var2"); + py_assert!(py, var1 other_var, "var1 != other_var"); + py_assert!(py, var1 var2, "(var1 != var2) == False"); + }) +} + +#[test] +fn test_enum_eq_incomparable() { + Python::with_gil(|py| { + let var1 = Py::new(py, MyEnum::Variant).unwrap(); + py_assert!(py, var1, "(var1 == 'foo') == False"); + py_assert!(py, var1, "(var1 != 'foo') == True"); + }) +} + #[pyfunction] fn return_enum() -> MyEnum { MyEnum::Variant @@ -70,7 +91,11 @@ fn test_custom_discriminant() { py_run!(py, CustomDiscriminant one two, r#" assert CustomDiscriminant.One == one assert CustomDiscriminant.Two == two + assert CustomDiscriminant.One == 1 + assert CustomDiscriminant.Two == 2 assert one != two + assert CustomDiscriminant.One != 2 + assert CustomDiscriminant.Two != 1 "#); }) } @@ -300,66 +325,6 @@ fn test_complex_enum_with_hash() { }); } -#[allow(deprecated)] -mod deprecated { - use crate::py_assert; - use pyo3::prelude::*; - use pyo3::py_run; - - #[pyclass] - #[derive(Debug, PartialEq, Eq, Clone)] - pub enum MyEnum { - Variant, - OtherVariant, - } - - #[test] - fn test_enum_eq_enum() { - Python::with_gil(|py| { - let var1 = Py::new(py, MyEnum::Variant).unwrap(); - let var2 = Py::new(py, MyEnum::Variant).unwrap(); - let other_var = Py::new(py, MyEnum::OtherVariant).unwrap(); - py_assert!(py, var1 var2, "var1 == var2"); - py_assert!(py, var1 other_var, "var1 != other_var"); - py_assert!(py, var1 var2, "(var1 != var2) == False"); - }) - } - - #[test] - fn test_enum_eq_incomparable() { - Python::with_gil(|py| { - let var1 = Py::new(py, MyEnum::Variant).unwrap(); - py_assert!(py, var1, "(var1 == 'foo') == False"); - py_assert!(py, var1, "(var1 != 'foo') == True"); - }) - } - - #[pyclass] - enum CustomDiscriminant { - One = 1, - Two = 2, - } - - #[test] - fn test_custom_discriminant() { - Python::with_gil(|py| { - #[allow(non_snake_case)] - let CustomDiscriminant = py.get_type::(); - let one = Py::new(py, CustomDiscriminant::One).unwrap(); - let two = Py::new(py, CustomDiscriminant::Two).unwrap(); - py_run!(py, CustomDiscriminant one two, r#" - assert CustomDiscriminant.One == one - assert CustomDiscriminant.Two == two - assert CustomDiscriminant.One == 1 - assert CustomDiscriminant.Two == 2 - assert one != two - assert CustomDiscriminant.One != 2 - assert CustomDiscriminant.Two != 1 - "#); - }) - } -} - #[test] fn custom_eq() { #[pyclass(frozen)] diff --git a/tests/ui/deprecations.rs b/tests/ui/deprecations.rs index da78a826cae..47b00d7eeee 100644 --- a/tests/ui/deprecations.rs +++ b/tests/ui/deprecations.rs @@ -25,10 +25,4 @@ fn pyfunction_option_4( ) { } -#[pyclass] -pub enum SimpleEnumWithoutEq { - VariamtA, - VariantB, -} - fn main() {} diff --git a/tests/ui/deprecations.stderr b/tests/ui/deprecations.stderr index 6236dc55631..0c65bd83417 100644 --- a/tests/ui/deprecations.stderr +++ b/tests/ui/deprecations.stderr @@ -27,11 +27,3 @@ error: use of deprecated constant `__pyfunction_pyfunction_option_4::SIGNATURE`: | 21 | fn pyfunction_option_4( | ^^^^^^^^^^^^^^^^^^^ - -error: use of deprecated method `pyo3::impl_::pyclass::Deprecation::autogenerated_equality`: Implicit equality for simple enums is deprecated. Use `#[pyclass(eq, eq_int)]` to keep the current behavior. - --> tests/ui/deprecations.rs:28:1 - | -28 | #[pyclass] - | ^^^^^^^^^^ - | - = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/invalid_proto_pymethods.stderr b/tests/ui/invalid_proto_pymethods.stderr index 18c96113299..82c99c2ddc3 100644 --- a/tests/ui/invalid_proto_pymethods.stderr +++ b/tests/ui/invalid_proto_pymethods.stderr @@ -40,17 +40,6 @@ note: candidate #2 is defined in an impl for the type `EqAndRichcmp` | ^^^^^^^^^^^^ = note: this error originates in the macro `::pyo3::impl_::pyclass::generate_pyclass_richcompare_slot` which comes from the expansion of the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0119]: conflicting implementations of trait `HasCustomRichCmp` for type `EqAndRichcmp` - --> tests/ui/invalid_proto_pymethods.rs:55:1 - | -55 | #[pymethods] - | ^^^^^^^^^^^^ - | | - | first implementation here - | conflicting implementation for `EqAndRichcmp` - | - = note: this error originates in the macro `::pyo3::impl_::pyclass::generate_pyclass_richcompare_slot` which comes from the expansion of the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0592]: duplicate definitions with name `__pymethod___richcmp____` --> tests/ui/invalid_proto_pymethods.rs:55:1 | diff --git a/tests/ui/invalid_pyclass_args.stderr b/tests/ui/invalid_pyclass_args.stderr index d1335e0f1a1..15aa0387cc6 100644 --- a/tests/ui/invalid_pyclass_args.stderr +++ b/tests/ui/invalid_pyclass_args.stderr @@ -162,17 +162,6 @@ error: The format string syntax cannot be used with enums 171 | #[pyclass(eq, str = "Stuff...")] | ^^^^^^^^^^ -error[E0119]: conflicting implementations of trait `HasCustomRichCmp` for type `EqOptAndManualRichCmp` - --> tests/ui/invalid_pyclass_args.rs:41:1 - | -37 | #[pyclass(eq)] - | -------------- first implementation here -... -41 | #[pymethods] - | ^^^^^^^^^^^^ conflicting implementation for `EqOptAndManualRichCmp` - | - = note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0592]: duplicate definitions with name `__pymethod___richcmp____` --> tests/ui/invalid_pyclass_args.rs:37:1 |