Fix type inference for index expression with bounded TypeVar (#11434)
Closes #8231
When type of index expression (e.g. `foo[bar]`) is analyzed and left
expression (i.e. `foo`) has generic type (`TypeVar`) with upper bound,
for some upper bound types this type inference yields wrong result.
For example, if upper bound type is instance of `TypeDict`, mypy
considers return type of such index expression as `object`:
```
from typing import TypedDict, TypeVar
class Data(TypedDict):
x: int
T = TypeVar("T", bound=Data)
def f(data: T) -> int:
# line below leads to mypy error:
# 'Unsupported operand types for + ("object" and "int")'
return data["x"] + 1
```
The root cause of this issue was in `visit_index_with_type` method
from `checkexpr.py` which does type analysis for index expressions. For
`TypeVar` left expression code flow goes via default branch which just
returns return type of upper bound's `__getitem__`. For some types this
return type inference logic operates on a fallback type. For example,
for `TypedDict` fallback type is `typing._TypedDict` with `__getitem__`
returning just `object`.
To fix the issue we added special case to `visit_index_with_type` for
`TypeVar` left expression which recursively calls
`visit_index_with_type` with `TypeVar` upper bound parameter. This way
we always handle upper bounds requiring special treatment correctly.
Corner case -- recursive TypeVar `T` with upper bound having
`__getitem__` method with `self` having type `T` and returning `T`.
In this case when we call `visit_index_with_type` recursively, `TypeVar`
types of upper bound `__getitem__` method are erased and
`check_method_call_by_name` returns type of upper bound, not `T`. So we
don't do recursive `visit_index_with_type` call when upper bound has
`__getitem__` method and handle this case in `else` branch. which
handles it as expected -- it return `T` as return type.