Skip to content

Commit 9681b54

Browse files
authored
Fix ambiguous associated item error (#4725)
* Add test for ambiguous associated item The `#[pyclass]` macro implements `IntoPyObject` for the annotated enum. When the enum has any of `Error`, `Output` or `Target` as members, this clashes with the associated types of `IntoPyObject`. This also happens when deriving `IntoPyObject` directly. * Fix #4723: ambiguous associated item in #[pyclass] This uses the fix described in rust-lang/rust#57644 Also apply fix to `#[derive(IntoPyObject)]`.
1 parent 06d2aff commit 9681b54

File tree

5 files changed

+42
-6
lines changed

5 files changed

+42
-6
lines changed

newsfragments/4725.fixed.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix `ambiguous_associated_items` lint error in `#[pyclass]` and `#[derive(IntoPyObject)]` macros.

pyo3-macros-backend/src/intopyobject.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ impl<'a> Enum<'a> {
512512
IntoPyObjectImpl {
513513
types: IntoPyObjectTypes::Opaque {
514514
target: quote!(#pyo3_path::types::PyAny),
515-
output: quote!(#pyo3_path::Bound<'py, Self::Target>),
515+
output: quote!(#pyo3_path::Bound<'py, <Self as #pyo3_path::conversion::IntoPyObject<'py>>::Target>),
516516
error: quote!(#pyo3_path::PyErr),
517517
},
518518
body: quote! {
@@ -617,7 +617,10 @@ pub fn build_derive_into_pyobject<const REF: bool>(tokens: &DeriveInput) -> Resu
617617
type Output = #output;
618618
type Error = #error;
619619

620-
fn into_pyobject(self, py: #pyo3_path::Python<#lt_param>) -> ::std::result::Result<Self::Output, Self::Error> {
620+
fn into_pyobject(self, py: #pyo3_path::Python<#lt_param>) -> ::std::result::Result<
621+
<Self as #pyo3_path::conversion::IntoPyObject>::Output,
622+
<Self as #pyo3_path::conversion::IntoPyObject>::Error,
623+
> {
621624
#body
622625
}
623626
}

pyo3-macros-backend/src/pyclass.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -1072,10 +1072,13 @@ fn impl_complex_enum(
10721072
quote! {
10731073
impl<'py> #pyo3_path::conversion::IntoPyObject<'py> for #cls {
10741074
type Target = Self;
1075-
type Output = #pyo3_path::Bound<'py, Self::Target>;
1075+
type Output = #pyo3_path::Bound<'py, <Self as #pyo3_path::conversion::IntoPyObject<'py>>::Target>;
10761076
type Error = #pyo3_path::PyErr;
10771077

1078-
fn into_pyobject(self, py: #pyo3_path::Python<'py>) -> ::std::result::Result<Self::Output, Self::Error> {
1078+
fn into_pyobject(self, py: #pyo3_path::Python<'py>) -> ::std::result::Result<
1079+
<Self as #pyo3_path::conversion::IntoPyObject>::Output,
1080+
<Self as #pyo3_path::conversion::IntoPyObject>::Error,
1081+
> {
10791082
match self {
10801083
#(#match_arms)*
10811084
}
@@ -2161,10 +2164,13 @@ impl<'a> PyClassImplsBuilder<'a> {
21612164

21622165
impl<'py> #pyo3_path::conversion::IntoPyObject<'py> for #cls {
21632166
type Target = Self;
2164-
type Output = #pyo3_path::Bound<'py, Self::Target>;
2167+
type Output = #pyo3_path::Bound<'py, <Self as #pyo3_path::conversion::IntoPyObject<'py>>::Target>;
21652168
type Error = #pyo3_path::PyErr;
21662169

2167-
fn into_pyobject(self, py: #pyo3_path::Python<'py>) -> ::std::result::Result<Self::Output, Self::Error> {
2170+
fn into_pyobject(self, py: #pyo3_path::Python<'py>) -> ::std::result::Result<
2171+
<Self as #pyo3_path::conversion::IntoPyObject>::Output,
2172+
<Self as #pyo3_path::conversion::IntoPyObject>::Error,
2173+
> {
21682174
#pyo3_path::Bound::new(py, self)
21692175
}
21702176
}

tests/test_compile_error.rs

+1
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,5 @@ fn test_compile_errors() {
6767
t.compile_fail("tests/ui/duplicate_pymodule_submodule.rs");
6868
#[cfg(all(not(Py_LIMITED_API), Py_3_11))]
6969
t.compile_fail("tests/ui/invalid_base_class.rs");
70+
t.pass("tests/ui/ambiguous_associated_items.rs");
7071
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use pyo3::prelude::*;
2+
3+
#[pyclass(eq)]
4+
#[derive(PartialEq)]
5+
pub enum SimpleItems {
6+
Error,
7+
Output,
8+
Target,
9+
}
10+
11+
#[pyclass]
12+
pub enum ComplexItems {
13+
Error(PyObject),
14+
Output(PyObject),
15+
Target(PyObject),
16+
}
17+
18+
#[derive(IntoPyObject)]
19+
enum DeriveItems {
20+
Error(PyObject),
21+
Output(PyObject),
22+
Target(PyObject),
23+
}
24+
25+
fn main() {}

0 commit comments

Comments
 (0)