-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Fix handling of default arguments in generated glue methods #10825
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
b44f26e
to
6edb06c
Compare
Thanks to @pranavrajpal for spotting this class of issues with forwarding default arguments! |
39be7a4
to
44626de
Compare
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 looks solid, excellent!
Glue method generation must be one of the trickiest things we do in mypyc. The PR is still pretty easy to understand because of the high-quality comments. I very much appreciate them.
I can imagine it would be quite hard to debug what went wrong if a user would hit a bug in the old implementation.
Just left a few minor comments about docstrings and tests.
has_star2: bool) -> Tuple[Optional[Value], Optional[Value]]: | ||
"""Construct *args and **kwargs from a collection of arguments | ||
|
||
This is pretty complicated, and almost all of the complication here stems from |
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 for writing such a detailed explanation! This really made it easier to figure what is going on.
Can you briefly also document has_star
and has_star2
?
|
||
z: Foo = Bar() | ||
z.f(1, z=2) | ||
z.f(1, 2, 3) |
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.
What about testing z.f(x=5)
?
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 didn't test that because we (knowingly) don't do the right thing: we forward it as a positional argument and not a keyword one. I added a comment.
z: Foo = Baz() | ||
z.f() | ||
z.f(y=1) | ||
z.f(1, 2) |
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.
What about z.f(x=7)
?
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.
Similar thing: in cpython this will raise a TypeError, since Baz.f wants the first argument to be a
, but we forward it as a positional argument and not a keyword one, so it actually works.
print("stuff", args, kwargs) | ||
|
||
z: Foo = Bar() | ||
z.f(1, z=50) |
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.
What about z.f(1)
or z.f(z=50)
?
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.
Added both
Currently these mostly segfault. The main tricky case here is with *args and **kwargs (which we need to deal with always when generating pycall glue and also when a native function takes them), though we also need to take care to coerce error values when forwarding optional arguments. I also accidentally fixed a bug where we would compile `f(a, *b, c)` as `f(a, c, *b)`.
Currently these mostly segfault.
The main tricky case here is with *args and **kwargs (which we need to
deal with always when generating pycall glue and also when a native
function takes them), though we also need to take care to coerce error
values when forwarding optional arguments.
I also accidentally fixed a bug where we would compile
f(a, *b, c)
as
f(a, c, *b)
.