-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Short term fix for bytes narrowing #20704
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
base: master
Are you sure you want to change the base?
Conversation
|
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅ |
I'm not so sure about this? Can we just treat all literals as being fine? x: bytes = b"blah"
y: bytes | None = b"blah"
if x == y:
reveal_type(y) # should reveal `bytes | None`
if b"blah" == y:
reveal_type(y) # should reveal `bytes`but that's also, not necessarily wrong: class X(bytes):
def __eq__(self, *args: object) -> bool:
return True
x: bytes = X(b"blah")
y: bytes | None = b"blah"
if x == y:
reveal_type(y) # yeah, it could be NoneIt's true that generally we're optimistic about whether something has a custom eq though, so I guess it doesn't matter. (e.g. you could substitute out a subclass for |
A5rocks
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.
This definitely solves the problem. I guess I'd be interested in something that recognizes:
x: bytes | bytearray | None = ...
if x == b"hello":
reveal_type(x) # should be bytes | bytearray
else:
reveal_type(x) # should be bytes | bytearray | Nonebut that's probably more complicated. (and just a bit more special casing)
|
Yes, we do indeed now have the behaviour from your test case in this PR
That's right. I'm not planning on trying this experiment, but given primer on my other custom equality changes maybe it is more viable than I would expect at first 😅
When I say this, I'm actually talking about bytearray and memoryview. As of this PR, we don't treat What we want is to have a reasonable way to teach mypy that memoryview will compare equal to bytes and bytearray, but not to other types. Similarly, int can compare equal to float and complex, but not to other types (currently trying to work through this in a principled way in my reachability PR that exposes a lot of messiness around here). Specifically, this Also we don't have the ideal behaviour on this snippet (which is fine on primer — I mean even this bytes change has no effect on primer — but still nice to have): (edit most of this was written before your second comment loaded) |
Fixes #20701 / see discussion there
Background:
__eq__, since they can compare equal to values that are of other types. I did this based on primer hits on draft versions of that PRtestNarrowingOptionalBytesbecause we're now more principled about custom__eq__. Perhaps interestingly the primer on that PR is small and not controversial, so I didn't feel the need to prioritise unsound thingsHowever, we only need one of the operands to have custom equality to model these things as reachable, so I think we can probably just remove
builtins.bytesfrom here.This behaviour still isn't ideal. For instance, narrowing here shouldn't depend on whether we promote or not (we shouldn't narrow
v_allto bytes with--strict-bytes)The real fix is adding more dedicated special casing so that we have an in-between option between "narrow assuming we can only compare equal to values of the same type" and "assume
__eq__means we can't conclude anything about the positive case"Other relevant PRs: