[ty] Make special cases for subscript inference exhaustive
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
# Subscripts involving type aliases
|
||||
|
||||
Aliases are expanded during analysis of subscripts.
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
```py
|
||||
from typing_extensions import TypeAlias, Literal
|
||||
|
||||
ImplicitTuple = tuple[str, int, int]
|
||||
PEP613Tuple: TypeAlias = tuple[str, int, int]
|
||||
type PEP695Tuple = tuple[str, int, int]
|
||||
|
||||
ImplicitZero = Literal[0]
|
||||
PEP613Zero: TypeAlias = Literal[0]
|
||||
type PEP695Zero = Literal[0]
|
||||
|
||||
def f(
|
||||
implicit_tuple: ImplicitTuple,
|
||||
pep_613_tuple: PEP613Tuple,
|
||||
pep_695_tuple: PEP695Tuple,
|
||||
implicit_zero: ImplicitZero,
|
||||
pep_613_zero: PEP613Zero,
|
||||
pep_695_zero: PEP695Zero,
|
||||
):
|
||||
reveal_type(implicit_tuple[:2]) # revealed: tuple[str, int]
|
||||
reveal_type(implicit_tuple[implicit_zero]) # revealed: str
|
||||
reveal_type(implicit_tuple[pep_613_zero]) # revealed: str
|
||||
reveal_type(implicit_tuple[pep_695_zero]) # revealed: str
|
||||
|
||||
reveal_type(pep_613_tuple[:2]) # revealed: tuple[str, int]
|
||||
reveal_type(pep_613_tuple[implicit_zero]) # revealed: str
|
||||
reveal_type(pep_613_tuple[pep_613_zero]) # revealed: str
|
||||
reveal_type(pep_613_tuple[pep_695_zero]) # revealed: str
|
||||
|
||||
reveal_type(pep_695_tuple[:2]) # revealed: tuple[str, int]
|
||||
reveal_type(pep_695_tuple[implicit_zero]) # revealed: str
|
||||
reveal_type(pep_695_tuple[pep_613_zero]) # revealed: str
|
||||
reveal_type(pep_695_tuple[pep_695_zero]) # revealed: str
|
||||
```
|
||||
@@ -106,5 +106,5 @@ class Bar:
|
||||
def f(x: Foo):
|
||||
if isinstance(x, Bar):
|
||||
# TODO: should be `int`
|
||||
reveal_type(x["whatever"]) # revealed: @Todo(Subscript expressions on intersections)
|
||||
reveal_type(x["whatever"]) # revealed: @Todo(Subscript expressions with intersections)
|
||||
```
|
||||
|
||||
@@ -80,6 +80,17 @@ def _(m: int, n: int, s2: str):
|
||||
reveal_type(substring2) # revealed: str
|
||||
```
|
||||
|
||||
## LiteralString
|
||||
|
||||
```py
|
||||
from typing_extensions import LiteralString
|
||||
|
||||
def f(x: LiteralString):
|
||||
reveal_type(x[0]) # revealed: LiteralString
|
||||
reveal_type(x[True]) # revealed: LiteralString
|
||||
reveal_type(x[1:42]) # revealed: LiteralString
|
||||
```
|
||||
|
||||
## Unsupported slice types
|
||||
|
||||
```py
|
||||
|
||||
@@ -430,5 +430,5 @@ class Bar: ...
|
||||
|
||||
def test4(val: Intersection[tuple[Foo], tuple[Bar]]):
|
||||
# TODO: should be `Foo & Bar`
|
||||
reveal_type(val[0]) # revealed: @Todo(Subscript expressions on intersections)
|
||||
reveal_type(val[0]) # revealed: @Todo(Subscript expressions with intersections)
|
||||
```
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
# Subscripts involving type variables
|
||||
|
||||
## TypeVar bound/constrained to a tuple/int-literal/bool-literal
|
||||
|
||||
The upper bounds of type variables are considered when analysing subscripts.
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
```py
|
||||
from typing_extensions import TypeAlias, Literal
|
||||
|
||||
ImplicitTuple = tuple[str, int, int]
|
||||
PEP613Tuple: TypeAlias = tuple[str, int, int]
|
||||
type PEP695Tuple = tuple[str, int, int]
|
||||
|
||||
ImplicitZero = Literal[0]
|
||||
PEP613Zero: TypeAlias = Literal[0]
|
||||
type PEP695Zero = Literal[0]
|
||||
|
||||
# fmt: off
|
||||
|
||||
def f[
|
||||
BoundedTupleT: tuple[str, int, bytes],
|
||||
ConstrainedTupleT: (tuple[str, int, bytes], tuple[int, bytes, str]),
|
||||
BoundedZeroT: Literal[0],
|
||||
ConstrainedIntLiteralT: (Literal[0], Literal[1])
|
||||
](
|
||||
tuple_1: BoundedTupleT,
|
||||
tuple_2: ConstrainedTupleT,
|
||||
zero: BoundedZeroT,
|
||||
some_integer: ConstrainedIntLiteralT,
|
||||
):
|
||||
# TODO: would ideally be `tuple[str, int]`
|
||||
reveal_type(tuple_1[:2]) # revealed: tuple[str | int | bytes, ...]
|
||||
reveal_type(tuple_1[zero]) # revealed: str
|
||||
|
||||
# TODO: ideally this might be `str | int`,
|
||||
# but it's hard to do that without introducing false positives elsewhere
|
||||
reveal_type(tuple_1[some_integer]) # revealed: str | int | bytes
|
||||
|
||||
# TODO: would ideally be `tuple[str, int] | tuple[int, bytes]`
|
||||
reveal_type(tuple_2[:2]) # revealed: tuple[str | int | bytes, ...]
|
||||
reveal_type(tuple_2[zero]) # revealed: str | int
|
||||
reveal_type(tuple_2[some_integer]) # revealed: str | int | bytes
|
||||
|
||||
# fmt: on
|
||||
```
|
||||
|
||||
## TypeVars
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
```py
|
||||
from typing import Protocol
|
||||
|
||||
class SupportsLessThan(Protocol):
|
||||
def __lt__(self, other, /) -> bool: ...
|
||||
|
||||
def f[K: SupportsLessThan](dictionary: dict[K, int], key: K):
|
||||
reveal_type(dictionary[key]) # revealed: int
|
||||
```
|
||||
|
||||
## ParamSpecs
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
```py
|
||||
from typing import Callable
|
||||
|
||||
def decorator[**P, T](func: Callable[P, T]) -> Callable[P, T]:
|
||||
def inner(*args: P.args, **kwargs: P.kwargs) -> T:
|
||||
if len(args) > 0:
|
||||
# error: [invalid-assignment]
|
||||
args = args[1:]
|
||||
|
||||
# `func` requires the full `ParamSpec` passed into `decorator`,
|
||||
# but here the first argument is skipped, so we should possibly emit an error here:
|
||||
return func(*args, **kwargs)
|
||||
return inner
|
||||
```
|
||||
Reference in New Issue
Block a user