-
Notifications
You must be signed in to change notification settings - Fork 676
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
Extend lifetime of holder references #3140
Conversation
@davidhewitt I wanted to push this here to ask your opinion of whether using local variables to extend the holder lifetimes is a suitable approach or whether we should do something else here entirely? |
6a681da
to
6735263
Compare
handle_error( | ||
extract_error_mode, | ||
py, | ||
quote! { | ||
_pyo3::impl_::extract_argument::extract_argument( | ||
#source, | ||
&mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT }, |
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 could not produce a test case actually triggering the issue but changed it for completeness. I did put it into a separate commit though if it turns out that we do not need this after all.
c3c890f
to
512f8ff
Compare
Ah, well found! So this is definitely a viable solution which has the nice property that it allows us to bind local variables inside the generated macro code. I think the other option is to avoid binding locals at all and just have one giant tail expression, because then the holder references will just be temporaries which will get extended until the end of the expression (by which point the return value has been converted into Python types). Something like this patch seems to fix the bug to me:
(This same trick might need applying in a few of the other code paths which you've corrected too.) Overall I'm happy with either approach. Being able to bind local variables makes the generated macro code easier for us to read and debug. On the other hand, the patch I put above keeps the implementation in |
I prepared #3142 with the tail-expression-based solution which is certainly a much smaller change and results less generated code which makes it the obvious choice for me. The only concern I am wrangling with myself is that it does seem like a "trick" to me and I would have a hard time inferring this effect by looking at the code. At least in this regard, I find the solution using local variables more pedestrian and more importantly explicit in that it is easier to understand why this is done. I am not completely convinced the effect is real though as I have never been on friendly terms with PyO3's proc macro code and this might just be me having a hard time doing anything with it. |
Ok - let's go with #3142 for now. I agree the macro implementations could use some refactoring, they've grown very... organically. 😅 What I'm hoping to move towards with that code is more structs which represent the parsed types, and then potentially more structs / functions to compose the generated code. E.g. this "ok-wrap and convert to PyErr" pattern can probably be its own function (or structure which implements |
Closes #3138