# Instance subscript

## `__getitem__` unbound

```py
class NotSubscriptable: ...

# snapshot: not-subscriptable
a = NotSubscriptable()[0]
```

```snapshot
error[not-subscriptable]: Cannot subscript object of type `NotSubscriptable` with no `__getitem__` method
 --> src/mdtest_snippet.py:4:5
  |
4 | a = NotSubscriptable()[0]
  |     ^^^^^^^^^^^^^^^^^^^^^
```

## `__getitem__` not callable

```py
class NotSubscriptable:
    __getitem__ = None

# TODO: this would be more user-friendly if the `call-non-callable` diagnostic was
# transformed into a `not-subscriptable` diagnostic with a subdiagnostic explaining
# that this was because `__getitem__` was possibly not callable
#
# error: [call-non-callable] "Method `__getitem__` of type `None | Unknown` may not be callable on object of type `NotSubscriptable`"
a = NotSubscriptable()[0]
```

## Valid `__getitem__`

```py
class Identity:
    def __getitem__(self, index: int) -> int:
        return index

reveal_type(Identity()[0])  # revealed: int
```

## Slice bounds for user-defined `__getitem__`

```py
class IntegerSlices:
    def __getitem__(self, key: slice[int | None, int | None, int | None]) -> str:
        return ""

class ArbitrarySlices:
    def __getitem__(self, key: slice) -> str:
        return ""

def _(
    integer_slices: IntegerSlices,
    arbitrary_slices: ArbitrarySlices,
    bound: object,
    invalid_bound: float,
) -> None:
    integer_slices[invalid_bound:]  # error: [invalid-argument-type]
    arbitrary_slices[bound:bound:bound]
```

## `__getitem__` union

```py
def _(flag: bool):
    class Identity:
        if flag:
            def __getitem__(self, index: int) -> int:
                return index

        else:
            def __getitem__(self, index: int) -> str:
                return str(index)

    reveal_type(Identity()[0])  # revealed: int | str
```

## Enum complement as overloaded `__getitem__` receiver

`overloaded.pyi`:

```pyi
from enum import Enum
from typing import Literal, overload

class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

    @overload
    def __getitem__(self: Literal[Color.GREEN], index: int) -> int: ...
    @overload
    def __getitem__(self: Literal[Color.BLUE], index: int) -> str: ...
```

```py
from overloaded import Color

def _(color: Color):
    if color is Color.RED:
        return
    reveal_type(color[0])  # revealed: int | str
```

## Enum complement as overloaded subscript mutation receiver

`overloaded.pyi`:

```pyi
from enum import Enum
from typing import Literal, overload

class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

    @overload
    def __setitem__(self: Literal[Color.GREEN], index: int, value: int) -> None: ...
    @overload
    def __setitem__(self: Literal[Color.BLUE], index: int, value: int) -> None: ...
    @overload
    def __delitem__(self: Literal[Color.GREEN], index: int) -> None: ...
    @overload
    def __delitem__(self: Literal[Color.BLUE], index: int) -> None: ...
```

```py
from typing import Literal

from overloaded import Color

def narrowed(color: Color):
    if color is Color.RED:
        return
    color[0] = 1
    del color[0]

def explicit(color: Literal[Color.GREEN, Color.BLUE]):
    color[0] = 1
    del color[0]
```

## `__getitem__` with invalid index argument

```py
class Identity:
    def __getitem__(self, index: int) -> int:
        return index

a = Identity()
# error: [invalid-argument-type] "Method `__getitem__` of type `bound method Identity.__getitem__(index: int) -> int` cannot be called with key of type `Literal["a"]` on object of type `Identity`"
a["a"]
```

## `__setitem__` with no `__getitem__`

```py
class NoGetitem:
    def __setitem__(self, index: int, value: int) -> None:
        pass

a = NoGetitem()
a[0] = 0
```

## Subscript store with no `__setitem__`

```py
class NoSetitem: ...

a = NoSetitem()
a[0] = 0  # error: "Cannot assign to a subscript on an object of type `NoSetitem`"
```

## `__setitem__` not callable

```py
class NoSetitem:
    __setitem__ = None

a = NoSetitem()
a[0] = 0  # error: "Method `__setitem__` of type `None | Unknown` may not be callable on object of type `NoSetitem`"
```

## Valid `__setitem__` method

```py
class Identity:
    def __setitem__(self, index: int, value: int) -> None:
        pass

a = Identity()
a[0] = 0
```

## `__setitem__` with invalid index argument

```py
class Identity:
    def __setitem__(self, index: int, value: int) -> None:
        pass

a = Identity()
# error: [invalid-assignment] "Invalid subscript assignment with key of type `Literal["a"]` and value of type `Literal[0]` on object of type `Identity`"
a["a"] = 0
```
