Skip to content

Commit

Permalink
A different approach
Browse files Browse the repository at this point in the history
  • Loading branch information
mejrs committed May 6, 2022
1 parent acae555 commit 63f67f1
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 41 deletions.
9 changes: 6 additions & 3 deletions pyo3-macros-backend/src/method.rs
Expand Up @@ -481,13 +481,16 @@ impl<'a> FnSpec<'a> {

// The method call is necessary to generate a decent error message.
let rust_call = quote! {
let ret = #rust_name(#self_arg #(#arg_names),*);
let mut ret = #rust_name(#self_arg #(#arg_names),*);

use _pyo3::callback::IntoPyResult;
let ret: _pyo3::PyResult<_> = ret.into_py_result();
if false {
use _pyo3::impl_::ghost::IntoPyResult;
ret.into_py_result();
}

_pyo3::callback::convert(#py, ret)
};

let krate = &self.krate;
Ok(match self.convention {
CallingConvention::Noargs => {
Expand Down
25 changes: 0 additions & 25 deletions src/callback.rs
Expand Up @@ -35,31 +35,6 @@ impl PyCallbackOutput for () {
const ERR_VALUE: Self = ();
}

/// A helper trait to result-wrap the return values of functions and methods.
#[doc(hidden)]
pub trait IntoPyResult<R> {
fn into_py_result(self) -> R;
}

impl<T> IntoPyResult<PyResult<T>> for T
where
T: IntoPy<PyObject>,
{
fn into_py_result(self) -> PyResult<Self> {
Ok(self)
}
}

impl<T, E> IntoPyResult<PyResult<T>> for Result<T, E>
where
T: IntoPy<PyObject>,
E: Into<PyErr>,
{
fn into_py_result(self) -> PyResult<T> {
self.map_err(Into::into)
}
}

/// Convert the result of callback function into the appropriate return value.
pub trait IntoPyCallbackOutput<Target> {
fn convert(self, py: Python<'_>) -> PyResult<Target>;
Expand Down
1 change: 1 addition & 0 deletions src/impl_.rs
Expand Up @@ -9,6 +9,7 @@ pub mod extract_argument;
pub mod freelist;
#[doc(hidden)]
pub mod frompyobject;
pub mod ghost;
pub(crate) mod not_send;
#[doc(hidden)]
pub mod pyclass;
Expand Down
19 changes: 19 additions & 0 deletions src/impl_/ghost.rs
@@ -0,0 +1,19 @@
/// If it does nothing, was it ever really there? 👻
///
/// This is code that is just type checked to e.g. create better compile errors,
/// but that never affects anything at runtime,
use crate::{IntoPy, PyErr, PyObject};

#[allow(clippy::wrong_self_convention)]
pub trait IntoPyResult<T> {
fn into_py_result(&mut self) {}
}

impl<T> IntoPyResult<T> for T where T: IntoPy<PyObject> {}

impl<T, E> IntoPyResult<T> for Result<T, E>
where
T: IntoPy<PyObject>,
E: Into<PyErr>,
{
}
24 changes: 17 additions & 7 deletions tests/ui/invalid_result_conversion.stderr
@@ -1,12 +1,22 @@
error[E0599]: the method `into_py_result` exists for enum `Result<(), MyError>`, but its trait bounds were not satisfied
error[E0599]: no method named `into_py_result` found for enum `Result` in the current scope
--> tests/ui/invalid_result_conversion.rs:21:1
|
21 | #[pyfunction]
| ^^^^^^^^^^^^^ method cannot be called on `Result<(), MyError>` due to unsatisfied trait bounds
| ^^^^^^^^^^^^^ method not found in `Result<(), MyError>`
|
= note: the following trait bounds were not satisfied:
`&Result<(), MyError>: IntoPy<Py<PyAny>>`
which is required by `&Result<(), MyError>: IntoPyResult<Result<&Result<(), MyError>, PyErr>>`
`&mut Result<(), MyError>: IntoPy<Py<PyAny>>`
which is required by `&mut Result<(), MyError>: IntoPyResult<Result<&mut Result<(), MyError>, PyErr>>`
= note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Result<(), MyError>: IntoPyCallbackOutput<_>` is not satisfied
--> tests/ui/invalid_result_conversion.rs:21:1
|
21 | #[pyfunction]
| ^^^^^^^^^^^^^ the trait `IntoPyCallbackOutput<_>` is not implemented for `Result<(), MyError>`
|
= help: the following implementations were found:
<Result<T, E> as IntoPyCallbackOutput<U>>
note: required by a bound in `pyo3::callback::convert`
--> src/callback.rs
|
| T: IntoPyCallbackOutput<U>,
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `pyo3::callback::convert`
= note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)
21 changes: 15 additions & 6 deletions tests/ui/missing_intopy.stderr
Expand Up @@ -6,18 +6,14 @@ error[E0599]: the method `into_py_result` exists for struct `Blah`, but its trai
| |
| method `into_py_result` not found for this
| doesn't satisfy `Blah: IntoPy<Py<PyAny>>`
| doesn't satisfy `Blah: IntoPyResult<Result<Blah, PyErr>>`
| doesn't satisfy `Blah: IntoPyResult<Blah>`
2 |
3 | #[pyo3::pyfunction]
| ^^^^^^^^^^^^^^^^^^^ method cannot be called on `Blah` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`Blah: IntoPy<Py<PyAny>>`
which is required by `Blah: IntoPyResult<Result<Blah, PyErr>>`
`&Blah: IntoPy<Py<PyAny>>`
which is required by `&Blah: IntoPyResult<Result<&Blah, PyErr>>`
`&mut Blah: IntoPy<Py<PyAny>>`
which is required by `&mut Blah: IntoPyResult<Result<&mut Blah, PyErr>>`
which is required by `Blah: IntoPyResult<Blah>`
note: the following trait must be implemented
--> src/conversion.rs
|
Expand All @@ -27,3 +23,16 @@ note: the following trait must be implemented
| | }
| |_^
= note: this error originates in the attribute macro `pyo3::pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Blah: IntoPyCallbackOutput<_>` is not satisfied
--> tests/ui/missing_intopy.rs:3:1
|
3 | #[pyo3::pyfunction]
| ^^^^^^^^^^^^^^^^^^^ the trait `IntoPyCallbackOutput<_>` is not implemented for `Blah`
|
note: required by a bound in `pyo3::callback::convert`
--> src/callback.rs
|
| T: IntoPyCallbackOutput<U>,
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `pyo3::callback::convert`
= note: this error originates in the attribute macro `pyo3::pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)

0 comments on commit 63f67f1

Please sign in to comment.