Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 3.1k
Special-case enum method calls#19634
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
Uh oh!
There was an error while loading. Please reload this page.
Conversation
ilevkivskyi commented Aug 10, 2025
Btw, this same idea can be applied for:
I will however defer these cases, unless I will find that mypy itself will benefit from these. |
ilevkivskyi commented Aug 10, 2025
Oh interesting, there is another 3.9 test failure because there is no Also, segfault happens after printing the traceback. I guess we add an incref too late for the method register (which only exists for non-extension classes) or for the class object register itself, or something similar. I will look tomorrow if there is a simple fix, if no simple fix, I will ignore this, as this is not related to my PR. |
ilevkivskyi commented Aug 10, 2025
I think I see the bug but |
ilevkivskyi commented Aug 10, 2025
It looks a bit trickier than that, in gdb I see segfault occurs on this line now here is a punishment for not writing docstrings :-) |
ilevkivskyi commented Aug 10, 2025
hm LOL doesn't look that way |
ilevkivskyi commented Aug 10, 2025
It looks like this was broken recently in #19307 cc @brianschubert |
ilevkivskyi commented Aug 10, 2025
Well, adding some conditional logic looks annoying, I guess we should simply skip adding |
ilevkivskyi commented Aug 10, 2025
Oh wait, this applies to extension classes as well. Then we should always allocate the docstring on the heap. @brandtbucher I hope you can fix this, segfault on an uncaught exception is a pretty bad behavior. TBH I still don't understand what exactly is going on, like why don't we have this problem if the program exits normally (i.e. without exception)? A minimal test to reproduce: generates |
brianschubert commented Aug 10, 2025 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
Still catching up, but would something like this do the trick? diff --git a/mypyc/lib-rt/misc_ops.c b/mypyc/lib-rt/misc_ops.c index 3787ea553..23981f9f3 100644 --- a/mypyc/lib-rt/misc_ops.c+++ b/mypyc/lib-rt/misc_ops.c@@ -300,6 +300,19 @@ PyObject *CPyType_FromTemplate(PyObject *template, Py_XDECREF(dummy_class); + if (template_->tp_doc){+ // Silently truncate the docstring if it contains a null byte+ Py_ssize_t size = strlen(template_->tp_doc) + 1;+ char *tp_doc = (char *)PyMem_Malloc(size);+ if (tp_doc == NULL){+ PyErr_NoMemory();+ goto error;+ }++ memcpy(tp_doc, template_->tp_doc, size);+ t->ht_type.tp_doc = tp_doc;+ }+ #if PY_MINOR_VERSION == 11 // This is a hack. Python 3.11 doesn't include good public APIs to work with managed // dicts, which are the default for heap types. So we try to opt-out until Python 3.12.Following after https://github.com/python/cpython/blob/485b16b4f7b28cefdfb524c2869d473078e349bf/Objects/typeobject.c#L4530-L4540 That seems to resolve the seg fault |
ilevkivskyi commented Aug 10, 2025
Yeah, that should work, I think we can simply add that chunk to |
ilevkivskyi commented Aug 10, 2025
(this however still doesn't explain why we don't fail without exception, this means we may have an extra incref for class objects, but this is a much smaller problem) |
…9636) See #19634 (comment) Also took the opportunity to add `PyDoc_STR` to the static docstrings. AFAIK this isn't strictly necessary, but it's better style and in theory makes it possible to compile without docstrings if someone wanted to do that.
sterliakov commented Aug 10, 2025
I also explored your options 1 and 3, with the same result for 1 and "no, doesn't look right" feeling regarding 3. Such duplication looks quite reasonable here - after all, normally enums are small and do not account for significant portion of a codebase, so this extra size should be negligible. I'll try to look deeper into this tonight, thanks! |
brandtbucher commented Aug 10, 2025
I'm guessing this is a misspelling of "@brianschubert"? Otherwise, sorry to disappoint, but I'm not sure how I can help with this issue specifically. :) |
ilevkivskyi commented Aug 10, 2025
@brandtbucher Oops, this is some serious misspelling, sorry :-) |
| [file driver.py] | ||
| from native import Test, C | ||
| assert Test.ONE.is_one() |
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 part of the test case isn't compiled -- is this intentional? Maybe move these to the compiled part of the test case under some test_<...> function?
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 was kind of intentional, as I wanted to test both compiled and interpreted calls, but I realised I only added one call in the compiled path (see definition of C.foo). I will add more calls there (to the overloaded method one etc).
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 added more asserts to foo() itself (note I call C().foo() manually in the driver).
982853d into python:masterUh oh!
There was an error while loading. Please reload this page.
Improves mypyc/mypyc#1121, this gives a bit above 1% on mypy self-check.
This only adds support for regular and overloaded methods without decorators (class/static methods and properties stay slow). When working on this I considered (and actually tried) four options:
__prepare__(), or don't call it at the right moment. Or maybe I just didn't try hard enough. In general, for some reason this feels risky.CPyDefs for (non-extension) enum methods, but since they have an extra argument,__mypyc_self__, we can supplyNULLthere, since we know it is unused. This is actually easy and it works, but IMO it is ultra-ugly, so I decided to not do it.CPyDefwithout__mypy_self__, use it for direct calls, and make existing callable classesCPyDefs one-line functions that simply call the first one. This is possible, but quite complicated, and I am not sure it is easy to generalize (e.g. on classmethods).