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

Expand wrap_pyfunction!() to a closure to improve deduction. #1597

Merged
merged 2 commits into from May 6, 2021

Conversation

m-ou-se
Copy link
Contributor

@m-ou-se m-ou-se commented May 6, 2021

This changes wrap_pyfunction!() to expand to a closure, to improve deduction when passed to a function without the GIL lifetime.

The change to wrap_pyfunction!() in #1143 makes it impossible to implement context.add_wrapped(wrap_pyfunction!(something)) in inline-python. context does not carry the GIL lifetime, which causes type deduction trouble now that wrap_pyfunction results in a generic function.

error[E0308]: mismatched types
  --> examples/rust-fn.rs:12:4
   |
12 |     c.add_wrapped(wrap_pyfunction!(rust_print));
   |       ^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected enum `Result<&pyo3::types::PyCFunction, _>`
              found enum `Result<&pyo3::types::PyCFunction, _>`

By re-wrapping the function as a closure, we trigger closure signature deduction instead of the regular deduction rules when passing wrap_pyfunction!() as an argument to a function: Rustc will deduce the signature of the closure from the bounds of the function that closure is passed to. This way, the generic arguments can be deduced in more contexts, fixing the problem.

The change to wrap_pyfunction!() in PyO3#1143 makes it impossible to
implement `context.add_wrapped(wrap_pyfunction!(something))` in
`inline-python`.
`context` does not carry the GIL lifetime, which causes type deduction
trouble now that `wrap_pyfunction` results in a generic function.

```
error[E0308]: mismatched types
  --> examples/rust-fn.rs:12:4
   |
12 |     c.add_wrapped(wrap_pyfunction!(rust_print));
   |       ^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected enum `Result<&pyo3::types::PyCFunction, _>`
              found enum `Result<&pyo3::types::PyCFunction, _>`
```

By re-wrapping the function as a closure, we trigger 'closure signature
deduction' when passing `wrap_pyfunction!()` as an argument to a
function: Rustc will deduce the signature of the closure from the
function that closure is passed to. This way, the generic arguments can
be deduced in more contexts, fixing the problem.
@m-ou-se m-ou-se force-pushed the wrap-pyfunction-as-closure branch from 2b0533c to 64e839d Compare May 6, 2021 14:03
Copy link
Member

@davidhewitt davidhewitt left a comment

Choose a reason for hiding this comment

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

Seems reasonable to me! Sneaky trick 👀

@davidhewitt davidhewitt merged commit 4edc7c6 into PyO3:main May 6, 2021
@m-ou-se m-ou-se deleted the wrap-pyfunction-as-closure branch May 6, 2021 22:47
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.

None yet

2 participants