With mypy in a generic class, the type of “args” is “tuple[Unpack[Ts`1]]” but the type of concatenated “args” is “builtins.tuple[builtins.object, ...]”

With mypy in a generic class, the type of “args” is “tuple[Unpack[Ts`1]]” but the type of concatenated “args” is “builtins.tuple[builtins.object, …]” as shown below:

class MyCls[*Ts]:

    def __init__(self, *args:*Ts) -> None:
        reveal_type(args)        # tuple[Unpack[Ts`1]]
        reveal_type(args + args) # builtins.tuple[builtins.object, ...]

MyCls[int, int, int](0, 1, 2)

Is it a normal behavior?

That’s a nice example - thanks.

Type checkers (like pyright and mypy) might infer more about args + args than reveal_type does.

The type checkers are what provides the implementation of reveal_type so different checkers give different answers:

$ mypy t.py
t.py:4: note: Revealed type is "tuple[Unpack[Ts`1]]"
t.py:5: note: Revealed type is "builtins.tuple[builtins.object, ...]"
Success: no issues found in 1 source file
$ pyright t.py
.../t.py
  .../t.py:4:21 - information: Type of "args" is "tuple[*Ts@MyCls]"
  .../t.py:5:21 - information: Type of "args + args" is "tuple[Union[*Ts@MyCls], ...]"
0 errors, 0 warnings, 2 informations 

I hadn’t realised that - thankyou.