-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
[mypyc] feat: call native __len__ when defined
#19934
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
Changes from all commits
8d6a97b
1986403
28abab5
0fae618
fff8658
3bb6177
d244e55
8e55b5e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,24 +1,92 @@ | ||
| # Test cases for (some) dunder methods | ||
|
|
||
| [case testDundersLen] | ||
| from typing import final | ||
|
|
||
| class C: | ||
| def __len__(self) -> int: | ||
| return 2 | ||
|
|
||
| @final | ||
| class D: | ||
| def __len__(self) -> int: | ||
| return 2 | ||
| class E: | ||
| @final | ||
| def __len__(self) -> int: | ||
| return 2 | ||
| class F(C): | ||
| """def __len__(self) -> int: | ||
| return 3""" | ||
| def f(c: C) -> int: | ||
| return len(c) | ||
| def g(d: D) -> int: | ||
| return len(d) | ||
| def h(e: E) -> int: | ||
| return len(e) | ||
| def i(f: F) -> int: | ||
| return len(f) | ||
| [out] | ||
| def C.__len__(self): | ||
| self :: __main__.C | ||
| L0: | ||
| return 4 | ||
| def D.__len__(self): | ||
| self :: __main__.D | ||
| L0: | ||
| return 4 | ||
| def E.__len__(self): | ||
| self :: __main__.E | ||
| L0: | ||
| return 4 | ||
| def f(c): | ||
| c :: __main__.C | ||
| r0 :: int | ||
| r1 :: bit | ||
| r2 :: bool | ||
| L0: | ||
| r0 = c.__len__() | ||
| r0 = C.__len__(c) | ||
| r1 = int_ge r0, 0 | ||
| if r1 goto L2 else goto L1 :: bool | ||
| L1: | ||
| r2 = raise ValueError('__len__() should return >= 0') | ||
| unreachable | ||
| L2: | ||
| return r0 | ||
| def g(d): | ||
| d :: __main__.D | ||
| r0 :: int | ||
| r1 :: bit | ||
| r2 :: bool | ||
| L0: | ||
| r0 = D.__len__(d) | ||
| r1 = int_ge r0, 0 | ||
| if r1 goto L2 else goto L1 :: bool | ||
| L1: | ||
| r2 = raise ValueError('__len__() should return >= 0') | ||
| unreachable | ||
| L2: | ||
| return r0 | ||
| def h(e): | ||
| e :: __main__.E | ||
| r0 :: int | ||
| r1 :: bit | ||
| r2 :: bool | ||
| L0: | ||
| r0 = E.__len__(e) | ||
| r1 = int_ge r0, 0 | ||
| if r1 goto L2 else goto L1 :: bool | ||
| L1: | ||
| r2 = raise ValueError('__len__() should return >= 0') | ||
| unreachable | ||
| L2: | ||
| return r0 | ||
| def i(f): | ||
| f :: __main__.F | ||
| r0 :: int | ||
| r1 :: bit | ||
| r2 :: bool | ||
| L0: | ||
| r0 = C.__len__(f) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this line should be But maybe its fine because
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mypyc performs static analysis on class hierarchies, and if you aren't doing separate compilation (most tests don't use it), it can identify all possible subclasses and thus determine that |
||
| r1 = int_ge r0, 0 | ||
| if r1 goto L2 else goto L1 :: bool | ||
| L1: | ||
|
|
||
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.
In a perfect world, should gen_method_call output the IR on the left or on the right?
I'll try to reimplement the logic from this PR in there and see what happens
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 in this case they should do the same thing, but the original IR is more consistent with the intent of the code, since we aren't calling a static method, so the it would be better.