allow `Bound<'_, T>` in #[pymethods] `self` position (#3896)

* allow `Bound<'_, T>` in #[pymethods] `self` position

* rename `TryFromPyCell` -> `TryFromBoundRef`

* remove unneccessary unsafe
This commit is contained in:
Icxolu 2024-02-25 08:13:36 +01:00 committed by GitHub
parent 8f1b99e1e9
commit 7c10ff4327
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 49 additions and 14 deletions

View File

@ -151,7 +151,7 @@ impl FnType {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum SelfType { pub enum SelfType {
Receiver { mutable: bool, span: Span }, Receiver { mutable: bool, span: Span },
TryFromPyCell(Span), TryFromBoundRef(Span),
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -204,15 +204,14 @@ impl SelfType {
) )
}) })
} }
SelfType::TryFromPyCell(span) => { SelfType::TryFromBoundRef(span) => {
error_mode.handle_error( error_mode.handle_error(
quote_spanned! { *span => quote_spanned! { *span =>
#py.from_borrowed_ptr::<_pyo3::PyAny>(#slf).downcast::<_pyo3::PyCell<#cls>>() _pyo3::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf).downcast::<#cls>()
.map_err(::std::convert::Into::<_pyo3::PyErr>::into) .map_err(::std::convert::Into::<_pyo3::PyErr>::into)
.and_then( .and_then(
#[allow(clippy::useless_conversion)] // In case slf is PyCell<Self>
#[allow(unknown_lints, clippy::unnecessary_fallible_conversions)] // In case slf is Py<Self> (unknown_lints can be removed when MSRV is 1.75+) #[allow(unknown_lints, clippy::unnecessary_fallible_conversions)] // In case slf is Py<Self> (unknown_lints can be removed when MSRV is 1.75+)
|cell| ::std::convert::TryFrom::try_from(cell).map_err(::std::convert::Into::into) |bound| ::std::convert::TryFrom::try_from(bound).map_err(::std::convert::Into::into)
) )
} }
@ -291,7 +290,7 @@ pub fn parse_method_receiver(arg: &syn::FnArg) -> Result<SelfType> {
if let syn::Type::ImplTrait(_) = &**ty { if let syn::Type::ImplTrait(_) = &**ty {
bail_spanned!(ty.span() => IMPL_TRAIT_ERR); bail_spanned!(ty.span() => IMPL_TRAIT_ERR);
} }
Ok(SelfType::TryFromPyCell(ty.span())) Ok(SelfType::TryFromBoundRef(ty.span()))
} }
} }
} }

View File

@ -1188,7 +1188,7 @@ fn complex_enum_variant_field_getter<'a>(
) -> Result<MethodAndMethodDef> { ) -> Result<MethodAndMethodDef> {
let signature = crate::pyfunction::FunctionSignature::from_arguments(vec![])?; let signature = crate::pyfunction::FunctionSignature::from_arguments(vec![])?;
let self_type = crate::method::SelfType::TryFromPyCell(field_span); let self_type = crate::method::SelfType::TryFromBoundRef(field_span);
let spec = FnSpec { let spec = FnSpec {
tp: crate::method::FnType::Getter(self_type.clone()), tp: crate::method::FnType::Getter(self_type.clone()),

View File

@ -3,10 +3,12 @@ use crate::exceptions::PyStopAsyncIteration;
use crate::gil::LockGIL; use crate::gil::LockGIL;
use crate::impl_::panic::PanicTrap; use crate::impl_::panic::PanicTrap;
use crate::internal_tricks::extract_c_string; use crate::internal_tricks::extract_c_string;
use crate::pycell::{PyBorrowError, PyBorrowMutError};
use crate::pyclass::boolean_struct::False;
use crate::types::{any::PyAnyMethods, PyModule, PyType}; use crate::types::{any::PyAnyMethods, PyModule, PyType};
use crate::{ use crate::{
ffi, Bound, Py, PyAny, PyCell, PyClass, PyErr, PyObject, PyResult, PyTraverseError, PyVisit, ffi, Bound, DowncastError, Py, PyAny, PyCell, PyClass, PyErr, PyObject, PyRef, PyRefMut,
Python, PyResult, PyTraverseError, PyTypeCheck, PyVisit, Python,
}; };
use std::borrow::Cow; use std::borrow::Cow;
use std::ffi::CStr; use std::ffi::CStr;
@ -490,6 +492,10 @@ impl<'a, 'py> BoundRef<'a, 'py, PyAny> {
Bound::ref_from_ptr_or_opt(py, ptr).as_ref().map(BoundRef) Bound::ref_from_ptr_or_opt(py, ptr).as_ref().map(BoundRef)
} }
pub fn downcast<T: PyTypeCheck>(self) -> Result<BoundRef<'a, 'py, T>, DowncastError<'a, 'py>> {
self.0.downcast::<T>().map(BoundRef)
}
pub unsafe fn downcast_unchecked<T>(self) -> BoundRef<'a, 'py, T> { pub unsafe fn downcast_unchecked<T>(self) -> BoundRef<'a, 'py, T> {
BoundRef(self.0.downcast_unchecked::<T>()) BoundRef(self.0.downcast_unchecked::<T>())
} }
@ -511,6 +517,36 @@ impl<'a> From<BoundRef<'a, 'a, PyModule>> for &'a PyModule {
} }
} }
impl<'a, 'py, T: PyClass> From<BoundRef<'a, 'py, T>> for &'a PyCell<T> {
#[inline]
fn from(bound: BoundRef<'a, 'py, T>) -> Self {
bound.0.as_gil_ref()
}
}
impl<'a, 'py, T: PyClass> TryFrom<BoundRef<'a, 'py, T>> for PyRef<'py, T> {
type Error = PyBorrowError;
#[inline]
fn try_from(value: BoundRef<'a, 'py, T>) -> Result<Self, Self::Error> {
value.0.clone().into_gil_ref().try_into()
}
}
impl<'a, 'py, T: PyClass<Frozen = False>> TryFrom<BoundRef<'a, 'py, T>> for PyRefMut<'py, T> {
type Error = PyBorrowMutError;
#[inline]
fn try_from(value: BoundRef<'a, 'py, T>) -> Result<Self, Self::Error> {
value.0.clone().into_gil_ref().try_into()
}
}
impl<'a, 'py, T> From<BoundRef<'a, 'py, T>> for Bound<'py, T> {
#[inline]
fn from(bound: BoundRef<'a, 'py, T>) -> Self {
bound.0.clone()
}
}
impl<'a, 'py, T> From<BoundRef<'a, 'py, T>> for &'a Bound<'py, T> { impl<'a, 'py, T> From<BoundRef<'a, 'py, T>> for &'a Bound<'py, T> {
#[inline] #[inline]
fn from(bound: BoundRef<'a, 'py, T>) -> Self { fn from(bound: BoundRef<'a, 'py, T>) -> Self {

View File

@ -654,7 +654,7 @@ impl<T: PyClass + fmt::Debug> fmt::Debug for PyCell<T> {
/// } /// }
/// # Python::with_gil(|py| { /// # Python::with_gil(|py| {
/// # let sub = Py::new(py, Child::new()).unwrap(); /// # let sub = Py::new(py, Child::new()).unwrap();
/// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 3)'"); /// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 4)'");
/// # }); /// # });
/// ``` /// ```
/// ///

View File

@ -1,8 +1,8 @@
error[E0277]: the trait bound `i32: From<&PyCell<MyClass>>` is not satisfied error[E0277]: the trait bound `i32: From<BoundRef<'_, '_, MyClass>>` is not satisfied
--> tests/ui/invalid_pymethod_receiver.rs:8:43 --> tests/ui/invalid_pymethod_receiver.rs:8:43
| |
8 | fn method_with_invalid_self_type(slf: i32, py: Python<'_>, index: u32) {} 8 | fn method_with_invalid_self_type(slf: i32, py: Python<'_>, index: u32) {}
| ^^^ the trait `From<&PyCell<MyClass>>` is not implemented for `i32` | ^^^ the trait `From<BoundRef<'_, '_, MyClass>>` is not implemented for `i32`
| |
= help: the following other types implement trait `From<T>`: = help: the following other types implement trait `From<T>`:
<i32 as From<bool>> <i32 as From<bool>>
@ -11,5 +11,5 @@ error[E0277]: the trait bound `i32: From<&PyCell<MyClass>>` is not satisfied
<i32 as From<u8>> <i32 as From<u8>>
<i32 as From<u16>> <i32 as From<u16>>
<i32 as From<NonZeroI32>> <i32 as From<NonZeroI32>>
= note: required for `&PyCell<MyClass>` to implement `Into<i32>` = note: required for `BoundRef<'_, '_, MyClass>` to implement `Into<i32>`
= note: required for `i32` to implement `TryFrom<&PyCell<MyClass>>` = note: required for `i32` to implement `TryFrom<BoundRef<'_, '_, MyClass>>`