-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Fix tuple[Any, ...] subtyping #16108
Fix tuple[Any, ...] subtyping #16108
Conversation
Follow up to python#16073 and python#16076 Fix needed for https://github.com/python/mypy/pull/16053/files#r1316481395 I add test cases that would have caught my previous incorrect PR. I add an explicit case for the new desirable behaviour we see with zip.
This comment has been minimized.
This comment has been minimized.
Hmm, this breaks commutativity of meet. Easy to make an ad hoc patch... |
2f1264b
to
c2250f8
Compare
This comment has been minimized.
This comment has been minimized.
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.
Generally looks good, but there are some suspicious parts, let's see what primer output will be after fixing these.
mypy/meet.py
Outdated
@@ -90,10 +90,15 @@ def meet_types(s: Type, t: Type) -> ProperType: | |||
return t | |||
|
|||
if not isinstance(s, UnboundType) and not isinstance(t, UnboundType): | |||
swap = isinstance(t, TupleType) and not isinstance(s, TupleType) | |||
if swap: | |||
s, t = t, s |
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 suspicious, the check below is for proper subtype, that should not now anything about Any
.
mypy/subtypes.py
Outdated
and len(left.args) == 1 | ||
and isinstance(get_proper_type(left.args[0]), AnyType) | ||
): | ||
return True |
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 this should return not self.proper_subtype
similar to above.
mypy/subtypes.py
Outdated
# TODO: we need a special case similar to above to consider (something that maps to) | ||
# tuple[Any, ...] a subtype of Tuple[<whatever>]. | ||
if ( | ||
left.type.fullname == "builtins.tuple" |
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 this should use has_base()
+ map_instance_to_supertype()
logic like above. Otherwise this breaks transitivity of subtyping.
test-data/unit/check-tuples.test
Outdated
takes_tuple_aa(inst_tuple_aa) | ||
takes_tuple_aa(inst_tuple_aa_subclass) | ||
# This next one should maybe not be an error | ||
takes_tuple_aa(inst_tuple_any_subclass) # E: Argument 1 to "takes_tuple_aa" has incompatible type "tuple_any_subclass"; expected "Tuple[A, A]" |
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 should be allowed (see above, if A <: B
and B <: C
, then A
must be <: C
).
This reverts commit c2250f8.
This comment has been minimized.
This comment has been minimized.
Thanks for the review! We lose several of the true positive warnings on pandas etc (the case tested by |
mypy/subtypes.py
Outdated
# TODO: we need a special case similar to above to consider (something that maps to) | ||
# tuple[Any, ...] a subtype of Tuple[<whatever>]. | ||
if ( | ||
mapped.type.has_base("builtins.tuple") |
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.
Why did you need the last commit? This condition is always true because of the surrounding if
(each tuple fallback has builtins.tuple
in MRO), and also now this check looks wrong because it may trigger in unrelated cases involving something like class M(Generic[T], tuple[int, ...]): ...
.
What you had before was almost right, except you didn't need the check len(mapped.args) == 1
, it should be always true if mapped.type.fullname == "builtins.tuple"
.
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 misinterpreted your comment here #16108 (comment)
Ugh, I tried to test the I can't actually find a test, even with various NamedTuplesclass M(Generic[T], tuple[int, ...]): ...
case but I did it backwards
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.
If you will not be able to come up with a test case, don't try to hard. It may be not easy to trigger such edge case (because of how user defined tuple types are represented). You already have enough test cases :-)
(I would still remove the unneeded len check)
This reverts commit 9840c37.
for more information, see https://pre-commit.ci
Diff from mypy_primer, showing the effect of this PR on open source code: mitmproxy (https://github.com/mitmproxy/mitmproxy)
+ mitmproxy/coretypes/multidict.py:153: error: Unused "type: ignore" comment [unused-ignore]
+ mitmproxy/coretypes/multidict.py:167: error: Unused "type: ignore" comment [unused-ignore]
+ mitmproxy/tools/console/grideditor/base.py:170: error: Unused "type: ignore" comment [unused-ignore]
Expression (https://github.com/cognitedata/Expression)
- expression/collections/block.py:814: error: Overloaded function implementation cannot produce return type of signature 1 [misc]
- expression/collections/block.py:814: error: Overloaded function implementation cannot produce return type of signature 2 [misc]
- expression/collections/block.py:814: error: Overloaded function implementation cannot produce return type of signature 3 [misc]
- expression/extra/parser.py:219: error: Overloaded function implementation cannot produce return type of signature 1 [misc]
- expression/extra/parser.py:219: error: Overloaded function implementation cannot produce return type of signature 2 [misc]
steam.py (https://github.com/Gobot1234/steam.py)
- steam/trade.py:321: error: Incompatible types in assignment (expression has type "tuple[Any, ...]", base class "Asset" defined the type as "tuple[str, str, str, str, str, str, str]") [assignment]
- steam/ext/csgo/backpack.py:263: error: Incompatible types in assignment (expression has type "tuple[Any, ...]", base class "Asset" defined the type as "tuple[str, str, str, str, str, str, str]") [assignment]
- steam/ext/csgo/backpack.py:330: error: Incompatible types in assignment (expression has type "tuple[Any, ...]", base class "Asset" defined the type as "tuple[str, str, str, str, str, str, str]") [assignment]
- steam/ext/csgo/backpack.py:330: error: Cannot determine type of "REPR_ATTRS" [has-type]
- steam/ext/tf2/backpack.py:80: error: Incompatible types in assignment (expression has type "tuple[Any, ...]", base class "Asset" defined the type as "tuple[str, str, str, str, str, str, str]") [assignment]
mypy (https://github.com/python/mypy)
+ mypy/main.py:1362: error: Unused "type: ignore" comment [unused-ignore]
operator (https://github.com/canonical/operator)
- ops/storage.py:191: error: Incompatible types in "yield" (actual type "tuple[Any, ...]", expected type "tuple[str, str, str]") [misc]
jax (https://github.com/google/jax)
+ jax/_src/scipy/special.py:293: error: Unused "type: ignore" comment [unused-ignore]
mongo-python-driver (https://github.com/mongodb/mongo-python-driver)
+ pymongo/mongo_client.py:1681: error: Unused "type: ignore" comment [unused-ignore]
ibis (https://github.com/ibis-project/ibis)
- ibis/util.py:126: error: Incompatible return value type (got "tuple[Any, ...]", expected "tuple[V]") [return-value]
- ibis/backends/oracle/__init__.py:51: error: Incompatible types in assignment (expression has type "tuple[Any, ...]", base class "ExprTranslator" defined the type as "tuple[type[Lag], type[Lead], type[DenseRank], type[MinRank], type[FirstValue], type[LastValue], type[PercentRank], type[CumeDist], type[NTile]]") [assignment]
- ibis/backends/trino/compiler.py:23: error: Incompatible types in assignment (expression has type "tuple[Any, ...]", base class "ExprTranslator" defined the type as "tuple[type[Lag], type[Lead], type[DenseRank], type[MinRank], type[FirstValue], type[LastValue], type[PercentRank], type[CumeDist], type[NTile]]") [assignment]
- ibis/backends/snowflake/__init__.py:58: error: Incompatible types in assignment (expression has type "tuple[Any, ...]", base class "ExprTranslator" defined the type as "tuple[type[Lag], type[Lead], type[DenseRank], type[MinRank], type[FirstValue], type[LastValue], type[PercentRank], type[CumeDist], type[NTile]]") [assignment]
|
Thank you! |
Follow up to #16073 and #16076
Fix needed for https://github.com/python/mypy/pull/16053/files#r1316481395
I add test cases that would have caught my previous incorrect PR. I add an explicit case for the new desirable behaviour we see with zip.