Skip to content

Commit

Permalink
Improve IntoPyCallbackOutput compile error
Browse files Browse the repository at this point in the history
  • Loading branch information
mejrs committed May 1, 2022
1 parent bcb1762 commit 139cae1
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 17 deletions.
12 changes: 10 additions & 2 deletions pyo3-macros-backend/src/method.rs
Expand Up @@ -478,8 +478,16 @@ impl<'a> FnSpec<'a> {
} else {
quote!(#func_name)
};
let rust_call =
quote! { _pyo3::callback::convert(#py, #rust_name(#self_arg #(#arg_names),*)) };

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

use _pyo3::callback::IntoResult;
let ret: _pyo3::PyResult<_> = ret.into_result();

_pyo3::callback::convert(#py, ret)
};
let krate = &self.krate;
Ok(match self.convention {
CallingConvention::Noargs => {
Expand Down
19 changes: 18 additions & 1 deletion pyo3-macros-backend/src/pymethod.rs
Expand Up @@ -495,6 +495,22 @@ pub fn impl_py_getter_def(cls: &syn::Type, property_type: PropertyType<'_>) -> R
self_type.receiver(cls, ExtractErrorMode::Raise)
}
};

let conversion = match property_type {
PropertyType::Descriptor { .. } => {
quote! {
let item: _pyo3::Py<_pyo3::PyAny> = _pyo3::IntoPy::into_py(item, _py);
::std::result::Result::Ok(_pyo3::conversion::IntoPyPointer::into_ptr(item))
}
}
// Forward to `IntoPyCallbackOutput`, to handle `#[getter]`s returning results.
PropertyType::Function { .. } => {
quote! {
_pyo3::callback::convert(_py, item)
}
}
};

Ok(quote! {
_pyo3::class::PyMethodDefType::Getter({
#deprecations
Expand All @@ -509,7 +525,8 @@ pub fn impl_py_getter_def(cls: &syn::Type, property_type: PropertyType<'_>) -> R
let _py = gil.python();
_pyo3::callback::panic_result_into_callback_output(_py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
#slf
_pyo3::callback::convert(_py, #getter_impl)
let item = #getter_impl;
#conversion
}))
}
__wrap
Expand Down
24 changes: 24 additions & 0 deletions src/callback.rs
Expand Up @@ -35,6 +35,30 @@ impl PyCallbackOutput for () {
const ERR_VALUE: Self = ();
}

#[doc(hidden)]
pub trait IntoResult<R> {
fn into_result(self) -> R;
}

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

impl<T, E> IntoResult<PyResult<T>> for Result<T, E>
where
T: IntoPy<PyObject>,
E: Into<PyErr>,
{
fn into_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
26 changes: 12 additions & 14 deletions tests/ui/invalid_result_conversion.stderr
@@ -1,14 +1,12 @@
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:182:8
|
182 | 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)
error[E0599]: the method `into_result` exists for enum `Result<(), MyError>`, but its trait bounds were not satisfied
--> tests/ui/invalid_result_conversion.rs:21:1
|
21 | #[pyfunction]
| ^^^^^^^^^^^^^ method cannot be called on `Result<(), MyError>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`&Result<(), MyError>: IntoPy<Py<PyAny>>`
which is required by `&Result<(), MyError>: IntoResult<Result<&Result<(), MyError>, PyErr>>`
`&mut Result<(), MyError>: IntoPy<Py<PyAny>>`
which is required by `&mut Result<(), MyError>: IntoResult<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)

0 comments on commit 139cae1

Please sign in to comment.