mypy
231f7cfa - Fix type inference for index expression with bounded TypeVar (#11434)

Commit
4 years ago
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.
Author
Parents
Loading