Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

better Some-wrapping for default arguments #3461

Merged
merged 1 commit into from
Sep 21, 2023

Conversation

davidhewitt
Copy link
Member

Closes #3460

This reworks the Some-wrapping of Option<T> default arguments to decide whether to wrap via a trait rather than searching for the text None. Most clear via the accompanying test; on main both b = Some(2) and d = NONE would be incorrectly double-wrapped.

Refactoring: I moved the ok-wrapping trait alongside this new trait for consistency. Perhaps in the future a refactoring will find a way to harmonise them.

Copy link
Member

@mejrs mejrs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is much better than the text based solution :)

Comment on lines +26 to +27
// The T: IntoPy<PyObject> bound here is necessary to prevent the
// implementation for Result<T, E> from conflicting
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it is not, this works today:

pub struct PyErr;
pub type PyResult<T> = Result<T, PyErr>;

pub trait OkWrap<T> {
    type Error;
    fn wrap(self) -> Result<T, Self::Error>;
}

impl<T> OkWrap<T> for T {
    type Error = PyErr;
    fn wrap(self) -> PyResult<T> {
        Ok(self)
    }
}

impl<T, E> OkWrap<T> for Result<T, E> {
    type Error = E;
    fn wrap(self) -> Result<T, Self::Error> {
        self
    }
}

I suspect the reason for the IntoPy<PyObject> bound is to generate a better error message, but I'm not sure.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I gave that a go just now and get some error messages like the following:

error[E0283]: type annotations needed
  --> src/test_hygiene/pyfunction.rs:4:1
   |
4  | #[crate::pyfunction]
   | ^^^^^^^^^^^^^^^^^^^^ cannot infer type
   |
note: multiple `impl`s satisfying `Result<i32, err::PyErr>: OkWrap<_>` found
  --> src/impl_/wrap.rs:26:1
   |
26 | impl<T> OkWrap<T> for T {
   | ^^^^^^^^^^^^^^^^^^^^^^^
...
33 | impl<T, E> OkWrap<T> for Result<T, E> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: this error originates in the attribute macro `crate::pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)

So it does seem that this bound avoids a conflict. Maybe in the future we can work out a simplification; I'll proceed to merge now to land the SomeWrap change.

@davidhewitt davidhewitt added this pull request to the merge queue Sep 21, 2023
Merged via the queue into PyO3:main with commit aeb7a95 Sep 21, 2023
@davidhewitt davidhewitt deleted the some-wraps branch September 21, 2023 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Type error when using (None) as the default value in function signature
2 participants