Fix Type Comparison Edge Cases#20277
Conversation
This comment has been minimized.
This comment has been minimized.
|
I don't quite understand what I should do with |
A5rocks
left a comment
There was a problem hiding this comment.
I'm not familiar with this part of mypy (this is the first time I saw TypeRange!), so my comments may be wrong. Initial pass through though.
I'm not sure about the bigger picture here, it feels somewhat hacky to rely on type(x) == Y logic to handle type(x) == type(y). I don't have any better ideas though.
This comment has been minimized.
This comment has been minimized.
|
Thanks for the PR! Also, just a short remark/question without any deep knowledge of the matter: If I understand #20275 correctly, calling |
|
@tyralla: Let me know if this makes it clear or if any of that doesn't make sense. |
|
Huh, then couldn't we get rid of any special casing for looking for specifically I imagine it's a bit strange (e.g. (I guess the flaw is actually that we need to know the relevant name to know what to narrow. Maybe that's why we don't do that) |
|
I never really thought about type narrowing with If I look at this example: class X: x = 1
class Y: y = 1
class Z(X, Y): ...
z = Z()
x: X = z
y: Y = z
if x is y:
x.y + y.x # error: "X" has no attribute "y"
# error: "Y" has no attribute "xI ask myself if Mypy should not handle it like: if isinstance(x, type(y)) and isinstance(y, type(x)):
x.y + y.xWhich could eventually easily be implemented with the help of |
I had a look at this and I've modified the implementation to allow this kind of checking. It just needs a bit of cleaning up. |
|
This cannot be directly handled here because class X: x = 1
class Y: y = 1
class Z(X, Y): ...
z = Z()
x: X = z
y: Y = z
if type(x) is type(y): # instead of x is y
x.y + y.x |
|
|
|
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Diff from mypy_primer, showing the effect of this PR on open source code: pandas (https://github.com/pandas-dev/pandas)
+ pandas/core/arrays/base.py:1502: error: Redundant cast to "ExtensionArray" [redundant-cast]
ibis (https://github.com/ibis-project/ibis)
- ibis/common/patterns.py:658: error: "Pattern" has no attribute "type" [attr-defined]
- ibis/common/patterns.py:934: error: "Pattern" has no attribute "patterns" [attr-defined]
jax (https://github.com/google/jax)
+ jax/_src/interpreters/partial_eval.py:96: error: Unused "type: ignore" comment [unused-ignore]
+ jax/_src/interpreters/partial_eval.py:99: error: No overload variant of "get" of "dict" matches argument types "int | DArray | Tracer | Var | DBIdx | InDBIdx | OutDBIdx", "int | DArray | Tracer | Var | DBIdx | InDBIdx | OutDBIdx" [call-overload]
+ jax/_src/interpreters/partial_eval.py:99: note: Possible overload variants:
+ jax/_src/interpreters/partial_eval.py:99: note: def get(self, Name, None = ..., /) -> DBIdx | None
+ jax/_src/interpreters/partial_eval.py:99: note: def get(self, Name, DBIdx, /) -> DBIdx
+ jax/_src/interpreters/partial_eval.py:99: note: def [_T] get(self, Name, _T, /) -> DBIdx | _T
+ jax/_src/interpreters/batching.py:231: error: Unused "type: ignore" comment [unused-ignore]
+ jax/_src/interpreters/batching.py:232: error: Unused "type: ignore" comment [unused-ignore]
+ jax/_src/interpreters/batching.py:234: error: No overload variant of "get" of "dict" matches argument types "int | DArray | Tracer | Var | DBIdx | InDBIdx | OutDBIdx", "int | DArray | Tracer | Var | DBIdx | InDBIdx | OutDBIdx" [call-overload]
+ jax/_src/interpreters/batching.py:234: note: Possible overload variants:
+ jax/_src/interpreters/batching.py:234: note: def get(self, Name, None = ..., /) -> DBIdx | None
+ jax/_src/interpreters/batching.py:234: note: def get(self, Name, DBIdx, /) -> DBIdx
+ jax/_src/interpreters/batching.py:234: note: def [_T] get(self, Name, _T, /) -> DBIdx | _T
+ jax/_src/interpreters/batching.py:258: error: Unused "type: ignore" comment [unused-ignore]
rotki (https://github.com/rotki/rotki)
+ rotkehlchen/history/events/structures/base.py:161: error: Unused "type: ignore" comment [unused-ignore]
+ rotkehlchen/history/events/structures/base.py:162: error: Unused "type: ignore" comment [unused-ignore]
+ rotkehlchen/history/events/structures/base.py:163: error: Unused "type: ignore" comment [unused-ignore]
+ rotkehlchen/history/events/structures/base.py:164: error: Unused "type: ignore" comment [unused-ignore]
+ rotkehlchen/history/events/structures/base.py:165: error: Unused "type: ignore" comment [unused-ignore]
+ rotkehlchen/history/events/structures/base.py:166: error: Unused "type: ignore" comment [unused-ignore]
+ rotkehlchen/history/events/structures/base.py:167: error: Unused "type: ignore" comment [unused-ignore]
+ rotkehlchen/history/events/structures/base.py:168: error: Unused "type: ignore" comment [unused-ignore]
+ rotkehlchen/history/events/structures/base.py:169: error: Unused "type: ignore" comment [unused-ignore]
+ rotkehlchen/history/events/structures/base.py:170: error: Unused "type: ignore" comment [unused-ignore]
+ rotkehlchen/history/events/structures/base.py:171: error: Unused "type: ignore" comment [unused-ignore]
+ rotkehlchen/history/events/structures/base.py:172: error: Unused "type: ignore" comment [unused-ignore]
pip (https://github.com/pypa/pip)
+ src/pip/_internal/utils/misc.py:551: error: Redundant cast to "HiddenText" [redundant-cast]
|
Test cases added from #20277 (initial PR) --------- Co-authored-by: hauntsaninja <hauntsaninja@gmail.com>
|
Thanks! I think all the test cases you'd talked about are handled on master. Do let me know if there is something on master that isn't working as intended! :-) |
Fixes #20275 and #20041
This code snippet fails to type-check before this PR:
But type-checks afterwards.
This is done by finding a least type as the upper bound when the equality succeeds.