mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 02:38:25 +00:00
[ty] add support for mapped union and intersection subscript loads (#18846)
## Summary Note this modifies the diagnostics a bit. Previously performing subscript access on something like `NotSubscriptable1 | NotSubscriptable2` would report the full type as not being subscriptable: ``` [non-subscriptable] "Cannot subscript object of type `NotSubscriptable1 | NotSubscriptable2` with no `__getitem__` method" ``` Now each erroneous constituent has a separate error: ``` [non-subscriptable] "Cannot subscript object of type `NotSubscriptable2` with no `__getitem__` method" [non-subscriptable] "Cannot subscript object of type `NotSubscriptable1` with no `__getitem__` method" ``` Closes https://github.com/astral-sh/ty/issues/625 ## Test Plan mdtest --------- Co-authored-by: Carl Meyer <carl@astral.sh>
This commit is contained in:
parent
a77db3da3f
commit
ef8281b695
5 changed files with 54 additions and 24 deletions
|
@ -63,12 +63,12 @@ def _(flag: bool):
|
|||
|
||||
else:
|
||||
class Spam: ...
|
||||
# error: [possibly-unbound-implicit-call] "Method `__class_getitem__` of type `<class 'Spam'> | <class 'Spam'>` is possibly unbound"
|
||||
# revealed: str
|
||||
# error: [non-subscriptable] "Cannot subscript object of type `<class 'Spam'>` with no `__class_getitem__` method"
|
||||
# revealed: str | Unknown
|
||||
reveal_type(Spam[42])
|
||||
```
|
||||
|
||||
## TODO: Class getitem non-class union
|
||||
## Class getitem non-class union
|
||||
|
||||
```py
|
||||
def _(flag: bool):
|
||||
|
@ -80,8 +80,7 @@ def _(flag: bool):
|
|||
else:
|
||||
Eggs = 1
|
||||
|
||||
a = Eggs[42] # error: "Cannot subscript object of type `<class 'Eggs'> | Literal[1]` with no `__getitem__` method"
|
||||
a = Eggs[42] # error: "Cannot subscript object of type `Literal[1]` with no `__getitem__` method"
|
||||
|
||||
# TODO: should _probably_ emit `str | Unknown`
|
||||
reveal_type(a) # revealed: Unknown
|
||||
reveal_type(a) # revealed: str | Unknown
|
||||
```
|
||||
|
|
|
@ -188,3 +188,30 @@ class C(Tuple): ...
|
|||
# revealed: tuple[<class 'C'>, <class 'tuple[Unknown, ...]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(C.__mro__)
|
||||
```
|
||||
|
||||
### Union subscript access
|
||||
|
||||
```py
|
||||
def test(val: tuple[str] | tuple[int]):
|
||||
reveal_type(val[0]) # revealed: str | int
|
||||
|
||||
def test2(val: tuple[str, None] | list[int | float]):
|
||||
reveal_type(val[0]) # revealed: str | int | float
|
||||
```
|
||||
|
||||
### Union subscript access with non-indexable type
|
||||
|
||||
```py
|
||||
def test3(val: tuple[str] | tuple[int] | int):
|
||||
# error: [non-subscriptable] "Cannot subscript object of type `int` with no `__getitem__` method"
|
||||
reveal_type(val[0]) # revealed: str | int | Unknown
|
||||
```
|
||||
|
||||
### Intersection subscript access
|
||||
|
||||
```py
|
||||
from ty_extensions import Intersection, Not
|
||||
|
||||
def test4(val: Intersection[tuple[str], tuple[int]]):
|
||||
reveal_type(val[0]) # revealed: str & int
|
||||
```
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue