mypy icon indicating copy to clipboard operation
mypy copied to clipboard

`tuple` instantiation ignores generics

Open DetachHead opened this issue 2 years ago • 5 comments

a = [1,2]
b: tuple[int, int] = tuple[int, int](a) # Incompatible types in assignment (expression has type "Tuple[int, ...]", variable has type "Tuple[int, int]")  [assignment]

playground

related: #15171

DetachHead avatar May 03 '23 03:05 DetachHead

um, I don't think there is a bug here? python list type is always variable length (https://docs.python.org/3/library/typing.html#annotating-tuples, not sure if there's a better reference)... in terms of the typing, the OP code is equivalent:

def f() -> list[int]: result = [] result.append(1) result.append(2) return result

b = tupleint, int

... and as a type checker I cannot tell how many elements are in f() so cannot guarantee that the b = line is correct.

For what it's worth, I think the only way to initialise a tuple[int, int] is to give it something that is guaranteed to have 2 elements; only tuple can give that guarantee. So you can write b = tuple[int, int]( (1, 2) ) for example.

urnest avatar Jun 17 '24 11:06 urnest

i don't remember raising this, but i think the confustion comes from the fact that mypy is special casing tuple. its definition in typeshed looks like this:

class tuple(Sequence[_T_co]):
    def __new__(cls, iterable: Iterable[_T_co] = ..., /) -> Self: ...

which normally would mean it only cares about the type inside the iterable, not its length, as eric traut said in https://github.com/python/mypy/issues/15171#issuecomment-1677919260.

DetachHead avatar Jun 17 '24 11:06 DetachHead

The issue is that:

a: list[int]
b = tuple[int, int](a)
reveal_type(b)  # builtins.tuple[builtins.int, ...]

The inferred type is NOT based on what was denoted(tuple[int, int]), instead being based on some special casing behavior.

Here is a better example:

a: list[str]
b = tuple[int, int](a)
reveal_type(b)  # builtins.tuple[builtins.str, ...]

c = list[int](a)
reveal_type(c)  # builtins.list[builtins.int, ...]

list is handled correctly, tuple is special cased and incorrect.

KotlinIsland avatar Jun 18 '24 00:06 KotlinIsland

yep, sorry, misinterpreted the OP - thanks for the clarifications

urnest avatar Jun 19 '24 10:06 urnest

current master (10f18a82b612b6127659cd64aa60c10b9cc7a904) I think gives (on the better example):

/home/xju/tmp/xxx.py:2:21: error: Argument 1 to "tuple" has incompatible type "list[str]"; expected "tuple[int, int]" [arg-type] /home/xju/tmp/xxx.py:3:13: note: Revealed type is "tuple[builtins.int, builtins.int]" /home/xju/tmp/xxx.py:5:15: error: Argument 1 to "list" has incompatible type "list[str]"; expected "Iterable[int]" [arg-type] /home/xju/tmp/xxx.py:6:13: note: Revealed type is "builtins.list[builtins.int]" Found 2 errors in 1 file (checked 1 source file)

... is that more like it?

urnest avatar Jun 19 '24 10:06 urnest