Skip to content

Commit 7bd8df8

Browse files
authored
switch deprecated implicit eq for simple enums (#4730)
1 parent 74ab0c0 commit 7bd8df8

File tree

9 files changed

+27
-167
lines changed

9 files changed

+27
-167
lines changed

newsfragments/4730.removed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Removed the deprecated implicit eq fallback for simple enums.

pyo3-macros-backend/src/pyclass.rs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,24 +1903,11 @@ fn pyclass_richcmp_simple_enum(
19031903
ensure_spanned!(options.eq.is_some(), eq_int.span() => "The `eq_int` option requires the `eq` option.");
19041904
}
19051905

1906-
let deprecation = (options.eq_int.is_none() && options.eq.is_none())
1907-
.then(|| {
1908-
quote! {
1909-
let _ = #pyo3_path::impl_::pyclass::DeprecationTest::<#cls>::new().autogenerated_equality();
1910-
}
1911-
})
1912-
.unwrap_or_default();
1913-
1914-
let mut options = options.clone();
1915-
if options.eq.is_none() {
1916-
options.eq_int = Some(parse_quote!(eq_int));
1917-
}
1918-
19191906
if options.eq.is_none() && options.eq_int.is_none() {
19201907
return Ok((None, None));
19211908
}
19221909

1923-
let arms = pyclass_richcmp_arms(&options, ctx)?;
1910+
let arms = pyclass_richcmp_arms(options, ctx)?;
19241911

19251912
let eq = options.eq.map(|eq| {
19261913
quote_spanned! { eq.span() =>
@@ -1954,8 +1941,6 @@ fn pyclass_richcmp_simple_enum(
19541941
other: &#pyo3_path::Bound<'_, #pyo3_path::PyAny>,
19551942
op: #pyo3_path::pyclass::CompareOp
19561943
) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
1957-
#deprecation
1958-
19591944
#eq
19601945

19611946
#eq_int

pyo3-macros-backend/src/pymethod.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,22 +1348,13 @@ impl SlotDef {
13481348
)?;
13491349
let name = spec.name;
13501350
let holders = holders.init_holders(ctx);
1351-
let dep = if method_name == "__richcmp__" {
1352-
quote! {
1353-
#[allow(unknown_lints, non_local_definitions)]
1354-
impl #pyo3_path::impl_::pyclass::HasCustomRichCmp for #cls {}
1355-
}
1356-
} else {
1357-
TokenStream::default()
1358-
};
13591351
let associated_method = quote! {
13601352
#[allow(non_snake_case)]
13611353
unsafe fn #wrapper_ident(
13621354
py: #pyo3_path::Python<'_>,
13631355
_raw_slf: *mut #pyo3_path::ffi::PyObject,
13641356
#(#arg_idents: #arg_types),*
13651357
) -> #pyo3_path::PyResult<#ret_ty> {
1366-
#dep
13671358
let function = #cls::#name; // Shadow the method name to avoid #3017
13681359
let _slf = _raw_slf;
13691360
#holders

src/impl_/pyclass.rs

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -878,8 +878,6 @@ macro_rules! generate_pyclass_richcompare_slot {
878878
other: *mut $crate::ffi::PyObject,
879879
op: ::std::os::raw::c_int,
880880
) -> *mut $crate::ffi::PyObject {
881-
impl $crate::impl_::pyclass::HasCustomRichCmp for $cls {}
882-
883881
$crate::impl_::trampoline::richcmpfunc(slf, other, op, |py, slf, other, op| {
884882
use $crate::class::basic::CompareOp;
885883
use $crate::impl_::pyclass::*;
@@ -1546,50 +1544,6 @@ impl<const IMPLEMENTS_INTOPYOBJECT: bool> ConvertField<false, IMPLEMENTS_INTOPYO
15461544
}
15471545
}
15481546

1549-
/// Marker trait whether a class implemented a custom comparison. Used to
1550-
/// silence deprecation of autogenerated `__richcmp__` for enums.
1551-
pub trait HasCustomRichCmp {}
1552-
1553-
/// Autoref specialization setup to emit deprecation warnings for autogenerated
1554-
/// pyclass equality.
1555-
pub struct DeprecationTest<T>(Deprecation, ::std::marker::PhantomData<T>);
1556-
pub struct Deprecation;
1557-
1558-
impl<T> DeprecationTest<T> {
1559-
#[inline]
1560-
#[allow(clippy::new_without_default)]
1561-
pub const fn new() -> Self {
1562-
DeprecationTest(Deprecation, ::std::marker::PhantomData)
1563-
}
1564-
}
1565-
1566-
impl<T> std::ops::Deref for DeprecationTest<T> {
1567-
type Target = Deprecation;
1568-
#[inline]
1569-
fn deref(&self) -> &Self::Target {
1570-
&self.0
1571-
}
1572-
}
1573-
1574-
impl<T> DeprecationTest<T>
1575-
where
1576-
T: HasCustomRichCmp,
1577-
{
1578-
/// For `HasCustomRichCmp` types; no deprecation warning.
1579-
#[inline]
1580-
pub fn autogenerated_equality(&self) {}
1581-
}
1582-
1583-
impl Deprecation {
1584-
#[deprecated(
1585-
since = "0.22.0",
1586-
note = "Implicit equality for simple enums is deprecated. Use `#[pyclass(eq, eq_int)]` to keep the current behavior."
1587-
)]
1588-
/// For types which don't implement `HasCustomRichCmp`; emits deprecation warning.
1589-
#[inline]
1590-
pub fn autogenerated_equality(&self) {}
1591-
}
1592-
15931547
#[cfg(test)]
15941548
#[cfg(feature = "macros")]
15951549
mod tests {

tests/test_enum.rs

Lines changed: 25 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,27 @@ fn test_enum_class_attr() {
2323
})
2424
}
2525

26+
#[test]
27+
fn test_enum_eq_enum() {
28+
Python::with_gil(|py| {
29+
let var1 = Py::new(py, MyEnum::Variant).unwrap();
30+
let var2 = Py::new(py, MyEnum::Variant).unwrap();
31+
let other_var = Py::new(py, MyEnum::OtherVariant).unwrap();
32+
py_assert!(py, var1 var2, "var1 == var2");
33+
py_assert!(py, var1 other_var, "var1 != other_var");
34+
py_assert!(py, var1 var2, "(var1 != var2) == False");
35+
})
36+
}
37+
38+
#[test]
39+
fn test_enum_eq_incomparable() {
40+
Python::with_gil(|py| {
41+
let var1 = Py::new(py, MyEnum::Variant).unwrap();
42+
py_assert!(py, var1, "(var1 == 'foo') == False");
43+
py_assert!(py, var1, "(var1 != 'foo') == True");
44+
})
45+
}
46+
2647
#[pyfunction]
2748
fn return_enum() -> MyEnum {
2849
MyEnum::Variant
@@ -70,7 +91,11 @@ fn test_custom_discriminant() {
7091
py_run!(py, CustomDiscriminant one two, r#"
7192
assert CustomDiscriminant.One == one
7293
assert CustomDiscriminant.Two == two
94+
assert CustomDiscriminant.One == 1
95+
assert CustomDiscriminant.Two == 2
7396
assert one != two
97+
assert CustomDiscriminant.One != 2
98+
assert CustomDiscriminant.Two != 1
7499
"#);
75100
})
76101
}
@@ -300,66 +325,6 @@ fn test_complex_enum_with_hash() {
300325
});
301326
}
302327

303-
#[allow(deprecated)]
304-
mod deprecated {
305-
use crate::py_assert;
306-
use pyo3::prelude::*;
307-
use pyo3::py_run;
308-
309-
#[pyclass]
310-
#[derive(Debug, PartialEq, Eq, Clone)]
311-
pub enum MyEnum {
312-
Variant,
313-
OtherVariant,
314-
}
315-
316-
#[test]
317-
fn test_enum_eq_enum() {
318-
Python::with_gil(|py| {
319-
let var1 = Py::new(py, MyEnum::Variant).unwrap();
320-
let var2 = Py::new(py, MyEnum::Variant).unwrap();
321-
let other_var = Py::new(py, MyEnum::OtherVariant).unwrap();
322-
py_assert!(py, var1 var2, "var1 == var2");
323-
py_assert!(py, var1 other_var, "var1 != other_var");
324-
py_assert!(py, var1 var2, "(var1 != var2) == False");
325-
})
326-
}
327-
328-
#[test]
329-
fn test_enum_eq_incomparable() {
330-
Python::with_gil(|py| {
331-
let var1 = Py::new(py, MyEnum::Variant).unwrap();
332-
py_assert!(py, var1, "(var1 == 'foo') == False");
333-
py_assert!(py, var1, "(var1 != 'foo') == True");
334-
})
335-
}
336-
337-
#[pyclass]
338-
enum CustomDiscriminant {
339-
One = 1,
340-
Two = 2,
341-
}
342-
343-
#[test]
344-
fn test_custom_discriminant() {
345-
Python::with_gil(|py| {
346-
#[allow(non_snake_case)]
347-
let CustomDiscriminant = py.get_type::<CustomDiscriminant>();
348-
let one = Py::new(py, CustomDiscriminant::One).unwrap();
349-
let two = Py::new(py, CustomDiscriminant::Two).unwrap();
350-
py_run!(py, CustomDiscriminant one two, r#"
351-
assert CustomDiscriminant.One == one
352-
assert CustomDiscriminant.Two == two
353-
assert CustomDiscriminant.One == 1
354-
assert CustomDiscriminant.Two == 2
355-
assert one != two
356-
assert CustomDiscriminant.One != 2
357-
assert CustomDiscriminant.Two != 1
358-
"#);
359-
})
360-
}
361-
}
362-
363328
#[test]
364329
fn custom_eq() {
365330
#[pyclass(frozen)]

tests/ui/deprecations.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,4 @@ fn pyfunction_option_4(
2525
) {
2626
}
2727

28-
#[pyclass]
29-
pub enum SimpleEnumWithoutEq {
30-
VariamtA,
31-
VariantB,
32-
}
33-
3428
fn main() {}

tests/ui/deprecations.stderr

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,3 @@ error: use of deprecated constant `__pyfunction_pyfunction_option_4::SIGNATURE`:
2727
|
2828
21 | fn pyfunction_option_4(
2929
| ^^^^^^^^^^^^^^^^^^^
30-
31-
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.
32-
--> tests/ui/deprecations.rs:28:1
33-
|
34-
28 | #[pyclass]
35-
| ^^^^^^^^^^
36-
|
37-
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)

tests/ui/invalid_proto_pymethods.stderr

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,6 @@ note: candidate #2 is defined in an impl for the type `EqAndRichcmp`
4040
| ^^^^^^^^^^^^
4141
= 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)
4242

43-
error[E0119]: conflicting implementations of trait `HasCustomRichCmp` for type `EqAndRichcmp`
44-
--> tests/ui/invalid_proto_pymethods.rs:55:1
45-
|
46-
55 | #[pymethods]
47-
| ^^^^^^^^^^^^
48-
| |
49-
| first implementation here
50-
| conflicting implementation for `EqAndRichcmp`
51-
|
52-
= 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)
53-
5443
error[E0592]: duplicate definitions with name `__pymethod___richcmp____`
5544
--> tests/ui/invalid_proto_pymethods.rs:55:1
5645
|

tests/ui/invalid_pyclass_args.stderr

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,6 @@ error: The format string syntax cannot be used with enums
162162
171 | #[pyclass(eq, str = "Stuff...")]
163163
| ^^^^^^^^^^
164164

165-
error[E0119]: conflicting implementations of trait `HasCustomRichCmp` for type `EqOptAndManualRichCmp`
166-
--> tests/ui/invalid_pyclass_args.rs:41:1
167-
|
168-
37 | #[pyclass(eq)]
169-
| -------------- first implementation here
170-
...
171-
41 | #[pymethods]
172-
| ^^^^^^^^^^^^ conflicting implementation for `EqOptAndManualRichCmp`
173-
|
174-
= note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info)
175-
176165
error[E0592]: duplicate definitions with name `__pymethod___richcmp____`
177166
--> tests/ui/invalid_pyclass_args.rs:37:1
178167
|

0 commit comments

Comments
 (0)