-
Notifications
You must be signed in to change notification settings - Fork 923
IntoPyObject for #[pyo3(get)]
#4449
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
Conversation
|
Hmm, not sure if there is a way to rewrite pub trait PyO3GetFieldIntoPyObject: for<'py> IntoPyObject<'py> + Clone
where
for<'py> <Self as IntoPyObject<'py>>::Error: Into<PyErr>,
{
}but this forces additional trait bounds on the usage site and causes the diagnostic of |
davidhewitt
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, thanks!
Hmm, not sure if there is a way to rewrite PyO3GetFieldIntoPyObject without associated type bounds
Hmm, I had a quick go just now but no obvious success, will continue to explore another rmoment.
src/impl_/pyclass.rs
Outdated
| let _holder = unsafe { | ||
| BoundRef::ref_from_ptr(py, &obj) | ||
| .downcast_unchecked::<ClassT>() | ||
| .try_borrow()? | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we now have a lot of repetition of this pattern, maybe refactor into a function? Possibly try of the offset operation just below also.
|
You can try using |
Given that |
I'm not particularly interested in putting in effort to prettify errors on old compilers. I would prefer having a simpler implementation. |
I think we mean the same thing, though the problem is that the trait exists to emit a diagnostic specific to this case! |
This could work, luckily associated type bounds were stabilized in 1.79 which is also the version we use for |
davidhewitt
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall this is looking good; just some final thoughts to refine this one off! 👀
src/impl_/pyclass.rs
Outdated
| where | ||
| ClassT: PyClass, | ||
| Offset: OffsetCalculator<ClassT, FieldT>, | ||
| FieldT: PyO3GetField, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there might be no need for this PyO3GetField trait any more, as it will never be used for a diagnostic? Might be able to simplify here.
| FieldT: PyO3GetField, | |
| FieldT: IntoPy<Py<PyAny>> + Clone |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might show if only IntoPy<PyObject> (and not IntoPyObject) is implemented while Clone is missing. But this is probably such a specific case (and we want people to use IntoPyObject anyway) that we should probably just remove it.
src/impl_/pyclass.rs
Outdated
| // The bound goes here rather than on the block so that this impl is always available | ||
| // if no specialization is used instead | ||
| where | ||
| FieldT: PyO3GetFieldIntoPyObject, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe if the other PyO3GetField trait can be removed, this one could be renamed to just PyO3GetField instead.
src/impl_/pyclass.rs
Outdated
| PyMethodDefType::Getter(PyGetterDef { | ||
| name, | ||
| meth: pyo3_get_value_into_pyobject::<ClassT, FieldT, Offset>, | ||
| doc, | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because there is a separate IntoPyObject + Clone case, this bound can never be satisfied, right?
| PyMethodDefType::Getter(PyGetterDef { | |
| name, | |
| meth: pyo3_get_value_into_pyobject::<ClassT, FieldT, Offset>, | |
| doc, | |
| }) | |
| unreachable!("exists purely to emit diagnostics on unimplemented traits") |
If so, I guess the same applies to the other cfg-d variant just above too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is true until we can remove the ToPyObject and IntoPy cases, at which point we can use this case, and remove the special case for IntoPyObject. If you prefer, we can put unreachable until then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I had to put panic since unreachable with a message is not allowed in const yet.
| = note: implement `ToPyObject` or `IntoPy<PyObject> + Clone` for `PhantomData<i32>` to define the conversion | ||
| = note: required for `PhantomData<i32>` to implement `PyO3GetField` | ||
| note: required by a bound in `PyClassGetterGenerator::<ClassT, FieldT, Offset, false, false>::generate` | ||
| = help: the trait `for<'py> IntoPyObject<'py>` is not implemented for `PhantomData<i32>`, which is required by `PhantomData<i32>: PyO3GetFieldIntoPyObject` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A thought: from testing locally, if I change the definition of PyO3GetFieldIntoPyObject to have a lifetime 'py, i.e. PyO3GetFieldIntoPyObject<'py>: IntoPyObject<'py> + Clone.
... then (after adjusting other uses accordingly), the error message looks more like this:
| = help: the trait `for<'py> IntoPyObject<'py>` is not implemented for `PhantomData<i32>`, which is required by `PhantomData<i32>: PyO3GetFieldIntoPyObject` | |
| = help: the trait `IntoPyObject<'_>` is not implemented for `PhantomData<i32>`, which is required by `for<'py> PhantomData<i32>: PyO3GetFieldIntoPyObject<'py>` |
Is that better? I think it might be slightly because it moves the HRTB later in the message. I think it's functionally equivalent otherwise?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be equivalent to put the HRTB in the method bound instead of the the super trait, yes.
davidhewitt
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this one looks great to me now!
This extends the
#[pyo3(get)]conversion specialization to includeIntoPyObject. I implemented the following priority list (or at least tried to 🙃 )Py<T>IntoPyObjectfor&TIntoPyObject + CloneforT(to prefer overIntoPy)ToPyObjectforTIntoPy + CloneforTIntoPyObject + CloneforT(currently only used to emit the correct diagnostic if no conversion trait is implemented)