mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 14:21:24 +00:00
[ty] Remove Type::Tuple
(#19669)
This commit is contained in:
parent
2abd683376
commit
d2fbf2af8f
27 changed files with 1189 additions and 1225 deletions
|
@ -183,33 +183,27 @@ def takes_at_least_two_positional_only(x: int, y: int, /, *args) -> None: ...
|
|||
class SingleElementTuple(tuple[int]): ...
|
||||
|
||||
def _(args: SingleElementTuple) -> None:
|
||||
# TODO: we should emit `[too-many-positional-arguments]` here
|
||||
takes_zero(*args)
|
||||
takes_zero(*args) # error: [too-many-positional-arguments]
|
||||
|
||||
takes_one(*args)
|
||||
|
||||
# TODO: we should emit `[missing-argument]` on both of these
|
||||
takes_two(*args)
|
||||
takes_two_positional_only(*args)
|
||||
takes_two(*args) # error: [missing-argument]
|
||||
takes_two_positional_only(*args) # error: [missing-argument]
|
||||
|
||||
# TODO: these should both be `[missing-argument]`, not `[invalid-argument-type]`
|
||||
takes_two_different(*args) # error: [invalid-argument-type]
|
||||
takes_two_different_positional_only(*args) # error: [invalid-argument-type]
|
||||
takes_two_different(*args) # error: [missing-argument]
|
||||
takes_two_different_positional_only(*args) # error: [missing-argument]
|
||||
|
||||
takes_at_least_zero(*args)
|
||||
takes_at_least_one(*args)
|
||||
|
||||
# TODO: we should emit `[missing-argument]` on both of these
|
||||
takes_at_least_two(*args)
|
||||
takes_at_least_two_positional_only(*args)
|
||||
takes_at_least_two(*args) # error: [missing-argument]
|
||||
takes_at_least_two_positional_only(*args) # error: [missing-argument]
|
||||
|
||||
class TwoElementIntTuple(tuple[int, int]): ...
|
||||
|
||||
def _(args: TwoElementIntTuple) -> None:
|
||||
# TODO: we should emit `[too-many-positional-arguments]` on both of these
|
||||
takes_zero(*args)
|
||||
takes_one(*args)
|
||||
|
||||
takes_zero(*args) # error: [too-many-positional-arguments]
|
||||
takes_one(*args) # error: [too-many-positional-arguments]
|
||||
takes_two(*args)
|
||||
takes_two_positional_only(*args)
|
||||
takes_two_different(*args) # error: [invalid-argument-type]
|
||||
|
@ -222,40 +216,23 @@ def _(args: TwoElementIntTuple) -> None:
|
|||
class IntStrTuple(tuple[int, str]): ...
|
||||
|
||||
def _(args: IntStrTuple) -> None:
|
||||
# TODO: we should emit `[too-many-positional-arguments]` here
|
||||
takes_zero(*args)
|
||||
takes_zero(*args) # error: [too-many-positional-arguments]
|
||||
|
||||
# TODO: this should be `[too-many-positional-arguments]`, not `[invalid-argument-type]`
|
||||
takes_one(*args) # error: [invalid-argument-type]
|
||||
takes_one(*args) # error: [too-many-positional-arguments]
|
||||
|
||||
# TODO: we should have one diagnostic for each of these, not two
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two(*args)
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two_positional_only(*args)
|
||||
|
||||
# TODO: these are all false positives
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two_different(*args)
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two_different_positional_only(*args)
|
||||
|
||||
takes_at_least_zero(*args)
|
||||
|
||||
# TODO: false positive
|
||||
# error: [invalid-argument-type]
|
||||
takes_at_least_one(*args)
|
||||
|
||||
# TODO: we should only emit one diagnostic for each of these, not two
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_at_least_two(*args)
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_at_least_two_positional_only(*args)
|
||||
```
|
||||
|
||||
|
@ -377,9 +354,7 @@ def takes_at_least_two_positional_only(x: int, y: int, /, *args) -> None: ...
|
|||
class IntStarInt(tuple[int, *tuple[int, ...]]): ...
|
||||
|
||||
def _(args: IntStarInt) -> None:
|
||||
# TODO: we should emit `[too-many-positional-arguments]` here
|
||||
takes_zero(*args)
|
||||
|
||||
takes_zero(*args) # error: [too-many-positional-arguments]
|
||||
takes_one(*args)
|
||||
takes_two(*args)
|
||||
takes_two_positional_only(*args)
|
||||
|
@ -393,50 +368,32 @@ def _(args: IntStarInt) -> None:
|
|||
class IntStarStr(tuple[int, *tuple[str, ...]]): ...
|
||||
|
||||
def _(args: IntStarStr) -> None:
|
||||
# TODO: we should emit `[too-many-positional-arguments]` here
|
||||
takes_zero(*args)
|
||||
takes_zero(*args) # error: [too-many-positional-arguments]
|
||||
|
||||
# TODO: false positive
|
||||
# error: [invalid-argument-type]
|
||||
takes_one(*args)
|
||||
|
||||
# TODO: we should only emit one diagnostic for each of these, not two
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two(*args)
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two_positional_only(*args)
|
||||
|
||||
# TODO: false positives
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two_different(*args)
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two_different_positional_only(*args)
|
||||
|
||||
takes_at_least_zero(*args)
|
||||
|
||||
# TODO: false positive
|
||||
# error: [invalid-argument-type]
|
||||
takes_at_least_one(*args)
|
||||
|
||||
# TODO: we should only have one diagnostic for each of these, not two
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_at_least_two(*args)
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_at_least_two_positional_only(*args)
|
||||
|
||||
class IntIntStarInt(tuple[int, int, *tuple[int, ...]]): ...
|
||||
|
||||
def _(args: IntIntStarInt) -> None:
|
||||
# TODO: we should emit `[too-many-positional-arguments]` on both of these
|
||||
takes_zero(*args)
|
||||
takes_one(*args)
|
||||
|
||||
takes_zero(*args) # error: [too-many-positional-arguments]
|
||||
takes_one(*args) # error: [too-many-positional-arguments]
|
||||
takes_two(*args)
|
||||
takes_two_positional_only(*args)
|
||||
takes_two_different(*args) # error: [invalid-argument-type]
|
||||
|
@ -449,51 +406,31 @@ def _(args: IntIntStarInt) -> None:
|
|||
class IntIntStarStr(tuple[int, int, *tuple[str, ...]]): ...
|
||||
|
||||
def _(args: IntIntStarStr) -> None:
|
||||
# TODO: we should emit `[too-many-positional-arguments]` here
|
||||
takes_zero(*args)
|
||||
takes_zero(*args) # error: [too-many-positional-arguments]
|
||||
|
||||
# TODO: this should be `[too-many-positional-arguments]`, not `invalid-argument-type`
|
||||
takes_one(*args) # error: [invalid-argument-type]
|
||||
takes_one(*args) # error: [too-many-positional-arguments]
|
||||
|
||||
# TODO: these are all false positives
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two(*args)
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two_positional_only(*args)
|
||||
|
||||
# TODO: each of these should only have one diagnostic, not two
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two_different(*args)
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two_different_positional_only(*args)
|
||||
|
||||
takes_at_least_zero(*args)
|
||||
|
||||
# TODO: false positive
|
||||
# error: [invalid-argument-type]
|
||||
takes_at_least_one(*args)
|
||||
|
||||
# TODO: these are both false positives
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_at_least_two(*args)
|
||||
|
||||
# TODO: these are both false positives
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_at_least_two_positional_only(*args)
|
||||
|
||||
class IntStarIntInt(tuple[int, *tuple[int, ...], int]): ...
|
||||
|
||||
def _(args: IntStarIntInt) -> None:
|
||||
# TODO: we should emit `[too-many-positional-arguments]` on both of these
|
||||
takes_zero(*args)
|
||||
takes_one(*args)
|
||||
|
||||
takes_zero(*args) # error: [too-many-positional-arguments]
|
||||
takes_one(*args) # error: [too-many-positional-arguments]
|
||||
takes_two(*args)
|
||||
takes_two_positional_only(*args)
|
||||
takes_two_different(*args) # error: [invalid-argument-type]
|
||||
|
@ -506,40 +443,25 @@ def _(args: IntStarIntInt) -> None:
|
|||
class IntStarStrInt(tuple[int, *tuple[str, ...], int]): ...
|
||||
|
||||
def _(args: IntStarStrInt) -> None:
|
||||
# TODO: we should emit `too-many-positional-arguments` here
|
||||
takes_zero(*args)
|
||||
takes_zero(*args) # error: [too-many-positional-arguments]
|
||||
|
||||
# TODO: this should be `too-many-positional-arguments`, not `invalid-argument-type`
|
||||
takes_one(*args) # error: [invalid-argument-type]
|
||||
takes_one(*args) # error: [too-many-positional-arguments]
|
||||
|
||||
# TODO: we should only emit one diagnostic for each of these
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two(*args)
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two_positional_only(*args)
|
||||
|
||||
# TODO: we should not emit diagnostics for these
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two_different(*args)
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_two_different_positional_only(*args)
|
||||
|
||||
takes_at_least_zero(*args)
|
||||
|
||||
# TODO: false positive
|
||||
takes_at_least_one(*args) # error: [invalid-argument-type]
|
||||
takes_at_least_one(*args)
|
||||
|
||||
# TODO: should only have one diagnostic here
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_at_least_two(*args)
|
||||
|
||||
# TODO: should only have one diagnostic here
|
||||
# error: [invalid-argument-type]
|
||||
# error: [invalid-argument-type]
|
||||
takes_at_least_two_positional_only(*args)
|
||||
```
|
||||
|
|
|
@ -411,10 +411,9 @@ def test_seq(x: Sequence[T]) -> Sequence[T]:
|
|||
return x
|
||||
|
||||
def func8(t1: tuple[complex, list[int]], t2: tuple[int, *tuple[str, ...]], t3: tuple[()]):
|
||||
# TODO: should be `Sequence[int | float | complex | list[int]]`
|
||||
reveal_type(test_seq(t1)) # revealed: Sequence[Unknown]
|
||||
# TODO: should be `Sequence[int | str]`
|
||||
reveal_type(test_seq(t2)) # revealed: Sequence[Unknown]
|
||||
reveal_type(test_seq(t1)) # revealed: Sequence[int | float | complex | list[int]]
|
||||
reveal_type(test_seq(t2)) # revealed: Sequence[int | str]
|
||||
|
||||
# TODO: this should be `Sequence[Never]`
|
||||
reveal_type(test_seq(t3)) # revealed: Sequence[Unknown]
|
||||
```
|
||||
|
|
|
@ -367,10 +367,9 @@ def test_seq[T](x: Sequence[T]) -> Sequence[T]:
|
|||
return x
|
||||
|
||||
def func8(t1: tuple[complex, list[int]], t2: tuple[int, *tuple[str, ...]], t3: tuple[()]):
|
||||
# TODO: should be `Sequence[int | float | complex | list[int]]`
|
||||
reveal_type(test_seq(t1)) # revealed: Sequence[Unknown]
|
||||
# TODO: should be `Sequence[int | str]`
|
||||
reveal_type(test_seq(t2)) # revealed: Sequence[Unknown]
|
||||
reveal_type(test_seq(t1)) # revealed: Sequence[int | float | complex | list[int]]
|
||||
reveal_type(test_seq(t2)) # revealed: Sequence[int | str]
|
||||
|
||||
# TODO: this should be `Sequence[Never]`
|
||||
reveal_type(test_seq(t3)) # revealed: Sequence[Unknown]
|
||||
```
|
||||
|
|
|
@ -23,6 +23,7 @@ We can then place custom stub files in `/typeshed/stdlib`, for example:
|
|||
|
||||
```pyi
|
||||
class object: ...
|
||||
class tuple: ...
|
||||
class BuiltinClass: ...
|
||||
|
||||
builtin_symbol: BuiltinClass
|
||||
|
@ -97,6 +98,12 @@ simple untyped definition is enough to make `reveal_type` work in tests:
|
|||
typeshed = "/typeshed"
|
||||
```
|
||||
|
||||
`/typeshed/stdlib/builtins.pyi`:
|
||||
|
||||
```pyi
|
||||
class tuple: ...
|
||||
```
|
||||
|
||||
`/typeshed/stdlib/typing_extensions.pyi`:
|
||||
|
||||
```pyi
|
||||
|
@ -104,5 +111,5 @@ def reveal_type(obj, /): ...
|
|||
```
|
||||
|
||||
```py
|
||||
reveal_type(()) # revealed: tuple[()]
|
||||
reveal_type(()) # revealed: tuple
|
||||
```
|
||||
|
|
|
@ -193,6 +193,7 @@ typeshed = "/typeshed"
|
|||
|
||||
```pyi
|
||||
class object: ...
|
||||
class tuple: ...
|
||||
class int: ...
|
||||
class bytes: ...
|
||||
|
||||
|
|
|
@ -39,9 +39,13 @@ class HeterogeneousSubclass0(tuple[()]): ...
|
|||
reveal_type(HeterogeneousSubclass0.__getitem__)
|
||||
|
||||
def f0(h0: HeterogeneousSubclass0, i: int):
|
||||
reveal_type(h0[0]) # revealed: Never
|
||||
reveal_type(h0[1]) # revealed: Never
|
||||
reveal_type(h0[-1]) # revealed: Never
|
||||
# error: [index-out-of-bounds]
|
||||
reveal_type(h0[0]) # revealed: Unknown
|
||||
# error: [index-out-of-bounds]
|
||||
reveal_type(h0[1]) # revealed: Unknown
|
||||
# error: [index-out-of-bounds]
|
||||
reveal_type(h0[-1]) # revealed: Unknown
|
||||
|
||||
reveal_type(h0[i]) # revealed: Never
|
||||
|
||||
class HeterogeneousSubclass1(tuple[I0]): ...
|
||||
|
@ -51,7 +55,8 @@ reveal_type(HeterogeneousSubclass1.__getitem__)
|
|||
|
||||
def f0(h1: HeterogeneousSubclass1, i: int):
|
||||
reveal_type(h1[0]) # revealed: I0
|
||||
reveal_type(h1[1]) # revealed: I0
|
||||
# error: [index-out-of-bounds]
|
||||
reveal_type(h1[1]) # revealed: Unknown
|
||||
reveal_type(h1[-1]) # revealed: I0
|
||||
reveal_type(h1[i]) # revealed: I0
|
||||
|
||||
|
@ -84,25 +89,19 @@ def g(m: MixedSubclass, i: int):
|
|||
reveal_type(m[2]) # revealed: I1 | I2 | I3
|
||||
reveal_type(m[3]) # revealed: I1 | I2 | I3
|
||||
reveal_type(m[4]) # revealed: I1 | I2 | I3 | I5
|
||||
reveal_type(m[5]) # revealed: I1 | I2 | I3 | I5
|
||||
reveal_type(m[10]) # revealed: I1 | I2 | I3 | I5
|
||||
|
||||
reveal_type(m[-1]) # revealed: I5
|
||||
reveal_type(m[-2]) # revealed: I2
|
||||
reveal_type(m[-3]) # revealed: I3
|
||||
reveal_type(m[-4]) # revealed: I2
|
||||
reveal_type(m[-5]) # revealed: I1 | I0
|
||||
reveal_type(m[-5]) # revealed: I0 | I1
|
||||
reveal_type(m[-6]) # revealed: I0 | I1
|
||||
reveal_type(m[-10]) # revealed: I0 | I1
|
||||
|
||||
reveal_type(m[i]) # revealed: I0 | I1 | I2 | I3 | I5
|
||||
|
||||
# Ideally we would not include `I0` in the unions for these,
|
||||
# but it's not possible to do this using only synthesized overloads.
|
||||
reveal_type(m[5]) # revealed: I0 | I1 | I2 | I3 | I5
|
||||
reveal_type(m[10]) # revealed: I0 | I1 | I2 | I3 | I5
|
||||
|
||||
# Similarly, ideally these would just be `I0` | I1`,
|
||||
# but achieving that with only synthesized overloads wouldn't be possible
|
||||
reveal_type(m[-6]) # revealed: I0 | I1 | I2 | I3 | I5
|
||||
reveal_type(m[-10]) # revealed: I0 | I1 | I2 | I3 | I5
|
||||
|
||||
class MixedSubclass2(tuple[I0, I1, *tuple[I2, ...], I3]): ...
|
||||
|
||||
# revealed: Overload[(self, index: Literal[0], /) -> I0, (self, index: Literal[-2], /) -> I2 | I1, (self, index: Literal[1], /) -> I1, (self, index: Literal[-3], /) -> I2 | I1 | I0, (self, index: Literal[-1], /) -> I3, (self, index: Literal[2], /) -> I2 | I3, (self, index: SupportsIndex, /) -> I0 | I1 | I2 | I3, (self, index: slice[Any, Any, Any], /) -> tuple[I0 | I1 | I2 | I3, ...]]
|
||||
|
@ -112,18 +111,12 @@ def g(m: MixedSubclass2, i: int):
|
|||
reveal_type(m[0]) # revealed: I0
|
||||
reveal_type(m[1]) # revealed: I1
|
||||
reveal_type(m[2]) # revealed: I2 | I3
|
||||
|
||||
# Ideally this would just be `I2 | I3`,
|
||||
# but that's not possible to achieve with synthesized overloads
|
||||
reveal_type(m[3]) # revealed: I0 | I1 | I2 | I3
|
||||
reveal_type(m[3]) # revealed: I2 | I3
|
||||
|
||||
reveal_type(m[-1]) # revealed: I3
|
||||
reveal_type(m[-2]) # revealed: I2 | I1
|
||||
reveal_type(m[-3]) # revealed: I2 | I1 | I0
|
||||
|
||||
# Ideally this would just be `I2 | I1 | I0`,
|
||||
# but that's not possible to achieve with synthesized overloads
|
||||
reveal_type(m[-4]) # revealed: I0 | I1 | I2 | I3
|
||||
reveal_type(m[-2]) # revealed: I1 | I2
|
||||
reveal_type(m[-3]) # revealed: I0 | I1 | I2
|
||||
reveal_type(m[-4]) # revealed: I0 | I1 | I2
|
||||
```
|
||||
|
||||
The stdlib API `os.stat` is a commonly used API that returns an instance of a tuple subclass
|
||||
|
@ -225,75 +218,47 @@ class I3: ...
|
|||
class HeterogeneousTupleSubclass(tuple[I0, I1, I2, I3]): ...
|
||||
|
||||
def __(t: HeterogeneousTupleSubclass, m: int, n: int):
|
||||
# TODO: should be `tuple[()]`
|
||||
reveal_type(t[0:0]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I0]`
|
||||
reveal_type(t[0:1]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I0, I1]`
|
||||
reveal_type(t[0:2]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be tuple[I0, I1, I2, I3]`
|
||||
reveal_type(t[0:4]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be tuple[I0, I1, I2, I3]`
|
||||
reveal_type(t[0:5]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I0, I1]`
|
||||
reveal_type(t[1:3]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
reveal_type(t[0:0]) # revealed: tuple[()]
|
||||
reveal_type(t[0:1]) # revealed: tuple[I0]
|
||||
reveal_type(t[0:2]) # revealed: tuple[I0, I1]
|
||||
reveal_type(t[0:4]) # revealed: tuple[I0, I1, I2, I3]
|
||||
reveal_type(t[0:5]) # revealed: tuple[I0, I1, I2, I3]
|
||||
reveal_type(t[1:3]) # revealed: tuple[I1, I2]
|
||||
|
||||
# TODO: should be `tuple[I2, I3]`
|
||||
reveal_type(t[-2:4]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I1, I2]`
|
||||
reveal_type(t[-3:-1]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I0, I1, I2, I3]`
|
||||
reveal_type(t[-10:10]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
reveal_type(t[-2:4]) # revealed: tuple[I2, I3]
|
||||
reveal_type(t[-3:-1]) # revealed: tuple[I1, I2]
|
||||
reveal_type(t[-10:10]) # revealed: tuple[I0, I1, I2, I3]
|
||||
|
||||
# TODO: should be `tuple[I0, I1, I2, I3]`
|
||||
reveal_type(t[0:]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I2, I3]`
|
||||
reveal_type(t[2:]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[()]`
|
||||
reveal_type(t[4:]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[()]`
|
||||
reveal_type(t[:0]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I0, I1]`
|
||||
reveal_type(t[:2]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I0, I1, I2, I3]`
|
||||
reveal_type(t[:10]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I0, I1, I2, I3]`
|
||||
reveal_type(t[:]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
reveal_type(t[0:]) # revealed: tuple[I0, I1, I2, I3]
|
||||
reveal_type(t[2:]) # revealed: tuple[I2, I3]
|
||||
reveal_type(t[4:]) # revealed: tuple[()]
|
||||
reveal_type(t[:0]) # revealed: tuple[()]
|
||||
reveal_type(t[:2]) # revealed: tuple[I0, I1]
|
||||
reveal_type(t[:10]) # revealed: tuple[I0, I1, I2, I3]
|
||||
reveal_type(t[:]) # revealed: tuple[I0, I1, I2, I3]
|
||||
|
||||
# TODO: should be `tuple[I3, I2, I1, I0]`
|
||||
reveal_type(t[::-1]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I0, I2]`
|
||||
reveal_type(t[::2]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I2, I1, I0]`
|
||||
reveal_type(t[-2:-5:-1]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I3, I1]`
|
||||
reveal_type(t[::-2]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I3, I0]`
|
||||
reveal_type(t[-1::-3]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
reveal_type(t[::-1]) # revealed: tuple[I3, I2, I1, I0]
|
||||
reveal_type(t[::2]) # revealed: tuple[I0, I2]
|
||||
reveal_type(t[-2:-5:-1]) # revealed: tuple[I2, I1, I0]
|
||||
reveal_type(t[::-2]) # revealed: tuple[I3, I1]
|
||||
reveal_type(t[-1::-3]) # revealed: tuple[I3, I0]
|
||||
|
||||
# TODO: should be `tuple[I0, I1]`
|
||||
reveal_type(t[None:2:None]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I1, I2, I3]`
|
||||
reveal_type(t[1:None:1]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I0, I1, I2, I3]`
|
||||
reveal_type(t[None:None:None]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
reveal_type(t[None:2:None]) # revealed: tuple[I0, I1]
|
||||
reveal_type(t[1:None:1]) # revealed: tuple[I1, I2, I3]
|
||||
reveal_type(t[None:None:None]) # revealed: tuple[I0, I1, I2, I3]
|
||||
|
||||
start = 1
|
||||
stop = None
|
||||
step = 2
|
||||
# TODO: should be `tuple[I1, I3]`
|
||||
reveal_type(t[start:stop:step]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
reveal_type(t[start:stop:step]) # revealed: tuple[I1, I3]
|
||||
|
||||
# TODO: should be `tuple[I0]`
|
||||
reveal_type(t[False:True]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
# TODO: should be `tuple[I1, I2]`
|
||||
reveal_type(t[True:3]) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
reveal_type(t[False:True]) # revealed: tuple[I0]
|
||||
reveal_type(t[True:3]) # revealed: tuple[I1, I2]
|
||||
|
||||
# TODO: we should emit `zero-stepsize-in-slice` on all of these:
|
||||
t[0:4:0]
|
||||
t[:4:0]
|
||||
t[0::0]
|
||||
t[::0]
|
||||
t[0:4:0] # error: [zero-stepsize-in-slice]
|
||||
t[:4:0] # error: [zero-stepsize-in-slice]
|
||||
t[0::0] # error: [zero-stepsize-in-slice]
|
||||
t[::0] # error: [zero-stepsize-in-slice]
|
||||
|
||||
tuple_slice = t[m:n]
|
||||
reveal_type(tuple_slice) # revealed: tuple[I0 | I1 | I2 | I3, ...]
|
||||
|
|
|
@ -502,10 +502,10 @@ For covariant types, such as `frozenset`, the ideal behaviour would be to not pr
|
|||
types to their instance supertypes: doing so causes more false positives than it fixes:
|
||||
|
||||
```py
|
||||
# TODO: should be `frozenset[Literal[1, 2, 3]]`
|
||||
reveal_type(frozenset((1, 2, 3))) # revealed: frozenset[Unknown]
|
||||
# TODO: should be `frozenset[tuple[Literal[1], Literal[2], Literal[3]]]`
|
||||
reveal_type(frozenset(((1, 2, 3),))) # revealed: frozenset[Unknown]
|
||||
# TODO: better here would be `frozenset[Literal[1, 2, 3]]`
|
||||
reveal_type(frozenset((1, 2, 3))) # revealed: frozenset[int]
|
||||
# TODO: better here would be `frozenset[tuple[Literal[1], Literal[2], Literal[3]]]`
|
||||
reveal_type(frozenset(((1, 2, 3),))) # revealed: frozenset[tuple[int, int, int]]
|
||||
```
|
||||
|
||||
Literals are always promoted for invariant containers such as `list`, however, even though this can
|
||||
|
@ -514,15 +514,15 @@ in some cases cause false positives:
|
|||
```py
|
||||
from typing import Literal
|
||||
|
||||
# TODO: should be `list[int]`
|
||||
reveal_type(list((1, 2, 3))) # revealed: list[Unknown]
|
||||
# TODO: should be `list[tuple[int, int, int]]`
|
||||
reveal_type(list(((1, 2, 3),))) # revealed: list[Unknown]
|
||||
reveal_type(list((1, 2, 3))) # revealed: list[int]
|
||||
reveal_type(list(((1, 2, 3),))) # revealed: list[tuple[int, int, int]]
|
||||
|
||||
# TODO: we could bidirectionally infer that the user does not want literals to be promoted here,
|
||||
# and avoid this diagnostic
|
||||
#
|
||||
# error: [invalid-assignment] "`list[int]` is not assignable to `list[Literal[1, 2, 3]]`"
|
||||
x: list[Literal[1, 2, 3]] = list((1, 2, 3))
|
||||
|
||||
# TODO: should be `list[Literal[1, 2, 3]]`
|
||||
reveal_type(x) # revealed: list[Unknown]
|
||||
reveal_type(x) # revealed: list[Literal[1, 2, 3]]
|
||||
```
|
||||
|
||||
[not a singleton type]: https://discuss.python.org/t/should-we-specify-in-the-language-reference-that-the-empty-tuple-is-a-singleton/67957
|
||||
|
|
|
@ -26,10 +26,8 @@ class HeterogeneousTupleSubclass(tuple[Literal[True], Literal[1]]): ...
|
|||
# from being overridden on a tuple subclass. This is something we plan to do as part of
|
||||
# our implementation of the Liskov Substitution Principle
|
||||
# (https://github.com/astral-sh/ty/issues/166)
|
||||
#
|
||||
# TODO: these should pass
|
||||
static_assert(is_single_valued(EmptyTupleSubclass)) # error: [static-assert-error]
|
||||
static_assert(is_single_valued(HeterogeneousTupleSubclass)) # error: [static-assert-error]
|
||||
static_assert(is_single_valued(EmptyTupleSubclass))
|
||||
static_assert(is_single_valued(HeterogeneousTupleSubclass))
|
||||
|
||||
static_assert(not is_single_valued(str))
|
||||
static_assert(not is_single_valued(Never))
|
||||
|
|
|
@ -424,142 +424,97 @@ class HeterogeneousTupleSubclass(tuple[I0, I1, I2]): ...
|
|||
|
||||
def f(x: HeterogeneousTupleSubclass):
|
||||
a, b, c = x
|
||||
reveal_type(a) # revealed: I0
|
||||
reveal_type(b) # revealed: I1
|
||||
reveal_type(c) # revealed: I2
|
||||
|
||||
# TODO: should be `I0`
|
||||
reveal_type(a) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I1`
|
||||
reveal_type(b) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I2`
|
||||
reveal_type(c) # revealed: I0 | I1 | I2
|
||||
d, e = x # error: [invalid-assignment] "Too many values to unpack: Expected 2"
|
||||
|
||||
# TODO: should emit a diagnostic ([invalid-assignment] "Too many values to unpack: Expected 2")
|
||||
d, e = x
|
||||
reveal_type(d) # revealed: Unknown
|
||||
reveal_type(e) # revealed: Unknown
|
||||
|
||||
reveal_type(d) # revealed: I0 | I1 | I2
|
||||
reveal_type(e) # revealed: I0 | I1 | I2
|
||||
f, g, h, i = x # error: [invalid-assignment] "Not enough values to unpack: Expected 4"
|
||||
|
||||
# TODO: should emit a diagnostic ([invalid-assignment] "Not enough values to unpack: Expected 4")
|
||||
f, g, h, i = x
|
||||
|
||||
reveal_type(f) # revealed: I0 | I1 | I2
|
||||
reveal_type(g) # revealed: I0 | I1 | I2
|
||||
reveal_type(h) # revealed: I0 | I1 | I2
|
||||
reveal_type(i) # revealed: I0 | I1 | I2
|
||||
reveal_type(f) # revealed: Unknown
|
||||
reveal_type(g) # revealed: Unknown
|
||||
reveal_type(h) # revealed: Unknown
|
||||
reveal_type(i) # revealed: Unknown
|
||||
|
||||
[j, *k] = x
|
||||
|
||||
# TODO: should be `I0`
|
||||
reveal_type(j) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `list[I1 | I2]`
|
||||
reveal_type(k) # revealed: list[I0 | I1 | I2]
|
||||
reveal_type(j) # revealed: I0
|
||||
reveal_type(k) # revealed: list[I1 | I2]
|
||||
|
||||
[l, m, *n] = x
|
||||
|
||||
# TODO: should be `I0`
|
||||
reveal_type(l) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I1`
|
||||
reveal_type(m) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `list[I2]`
|
||||
reveal_type(n) # revealed: list[I0 | I1 | I2]
|
||||
reveal_type(l) # revealed: I0
|
||||
reveal_type(m) # revealed: I1
|
||||
reveal_type(n) # revealed: list[I2]
|
||||
|
||||
[o, p, q, *r] = x
|
||||
reveal_type(o) # revealed: I0
|
||||
reveal_type(p) # revealed: I1
|
||||
reveal_type(q) # revealed: I2
|
||||
reveal_type(r) # revealed: list[Never]
|
||||
|
||||
# TODO: should be `I0`
|
||||
reveal_type(o) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I1`
|
||||
reveal_type(p) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I2`
|
||||
reveal_type(q) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `list[Never]`
|
||||
reveal_type(r) # revealed: list[I0 | I1 | I2]
|
||||
|
||||
# TODO: should emit a diagnostic ([invalid-assignment] "Not enough values to unpack: Expected at least 4")
|
||||
# error: [invalid-assignment] "Not enough values to unpack: Expected at least 4"
|
||||
[s, t, u, v, *w] = x
|
||||
reveal_type(s) # revealed: I0 | I1 | I2
|
||||
reveal_type(t) # revealed: I0 | I1 | I2
|
||||
reveal_type(u) # revealed: I0 | I1 | I2
|
||||
reveal_type(v) # revealed: I0 | I1 | I2
|
||||
reveal_type(w) # revealed: list[I0 | I1 | I2]
|
||||
reveal_type(s) # revealed: Unknown
|
||||
reveal_type(t) # revealed: Unknown
|
||||
reveal_type(u) # revealed: Unknown
|
||||
reveal_type(v) # revealed: Unknown
|
||||
reveal_type(w) # revealed: list[Unknown]
|
||||
|
||||
class MixedTupleSubclass(tuple[I0, *tuple[I1, ...], I2]): ...
|
||||
|
||||
def f(x: MixedTupleSubclass):
|
||||
# TODO: should emit a diagnostic: ([invalid-assignment] "Too many values to unpack: Expected 1"`)
|
||||
(a,) = x
|
||||
reveal_type(a) # revealed: I0 | I1 | I2
|
||||
(a,) = x # error: [invalid-assignment] "Too many values to unpack: Expected 1"
|
||||
reveal_type(a) # revealed: Unknown
|
||||
|
||||
c, d = x
|
||||
# TODO: should be `I0`
|
||||
reveal_type(c) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I2`
|
||||
reveal_type(d) # revealed: I0 | I1 | I2
|
||||
reveal_type(c) # revealed: I0
|
||||
reveal_type(d) # revealed: I2
|
||||
|
||||
e, f, g = x
|
||||
|
||||
# TODO: should be `I0`
|
||||
reveal_type(e) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I1`
|
||||
reveal_type(f) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I2`
|
||||
reveal_type(g) # revealed: I0 | I1 | I2
|
||||
reveal_type(e) # revealed: I0
|
||||
reveal_type(f) # revealed: I1
|
||||
reveal_type(g) # revealed: I2
|
||||
|
||||
h, i, j, k = x
|
||||
|
||||
# TODO: should be `I0`
|
||||
reveal_type(h) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I1`
|
||||
reveal_type(i) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I1`
|
||||
reveal_type(j) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I2`
|
||||
reveal_type(k) # revealed: I0 | I1 | I2
|
||||
reveal_type(h) # revealed: I0
|
||||
reveal_type(i) # revealed: I1
|
||||
reveal_type(j) # revealed: I1
|
||||
reveal_type(k) # revealed: I2
|
||||
|
||||
[l, *m] = x
|
||||
|
||||
# TODO: should be `I0`
|
||||
reveal_type(l) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `list[I1 | I2]`
|
||||
reveal_type(m) # revealed: list[I0 | I1 | I2]
|
||||
reveal_type(l) # revealed: I0
|
||||
reveal_type(m) # revealed: list[I1 | I2]
|
||||
|
||||
[n, o, *p] = x
|
||||
reveal_type(n) # revealed: I0
|
||||
|
||||
# TODO: should be `I0`
|
||||
reveal_type(n) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I1 | I2`
|
||||
reveal_type(o) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `list[I1 | I2]`
|
||||
reveal_type(p) # revealed: list[I0 | I1 | I2]
|
||||
# TODO: `I1 | I2` might be better here? (https://github.com/astral-sh/ty/issues/947)
|
||||
reveal_type(o) # revealed: I1
|
||||
|
||||
reveal_type(p) # revealed: list[I1 | I2]
|
||||
|
||||
[o, p, q, *r] = x
|
||||
reveal_type(o) # revealed: I0
|
||||
|
||||
# TODO: should be `I0`
|
||||
reveal_type(o) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I1 | I2`
|
||||
reveal_type(p) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I1 | I2
|
||||
reveal_type(q) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `list[I1 | I2]
|
||||
reveal_type(r) # revealed: list[I0 | I1 | I2]
|
||||
# TODO: `I1 | I2` might be better for both of these? (https://github.com/astral-sh/ty/issues/947)
|
||||
reveal_type(p) # revealed: I1
|
||||
reveal_type(q) # revealed: I1
|
||||
|
||||
reveal_type(r) # revealed: list[I1 | I2]
|
||||
|
||||
s, *t, u = x
|
||||
|
||||
# TODO: should be `I0`
|
||||
reveal_type(s) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `list[I1]`
|
||||
reveal_type(t) # revealed: list[I0 | I1 | I2]
|
||||
# TODO: should be `I2`
|
||||
reveal_type(u) # revealed: I0 | I1 | I2
|
||||
reveal_type(s) # revealed: I0
|
||||
reveal_type(t) # revealed: list[I1]
|
||||
reveal_type(u) # revealed: I2
|
||||
|
||||
aa, bb, *cc, dd = x
|
||||
|
||||
# TODO: should be `I0`
|
||||
reveal_type(aa) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `I1`
|
||||
reveal_type(bb) # revealed: I0 | I1 | I2
|
||||
# TODO: should be `list[I1]`
|
||||
reveal_type(cc) # revealed: list[I0 | I1 | I2]
|
||||
# TODO: should be I2
|
||||
reveal_type(dd) # revealed: I0 | I1 | I2
|
||||
reveal_type(aa) # revealed: I0
|
||||
reveal_type(bb) # revealed: I1
|
||||
reveal_type(cc) # revealed: list[I1]
|
||||
reveal_type(dd) # revealed: I2
|
||||
```
|
||||
|
||||
## String
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue