Mypy does not correctly narrow indexing operations when using Literal or Final keys
まだ誰も着手していません。
- 主要言語
- Python
- スター
- 20.6k
- フォーク
- 3.3k
- PR マージ指標
- PR 指標を取得中
説明
Consider the following program:
from typing_extensions import Literal, TypedDict
from enum import Enum
class Key(Enum):
X = 1
Y = 2
Z = 3
class MyDict(TypedDict):
key: Literal[Key.X, Key.Y]
blah: int
KEY: Literal["key"] = "key"
d: MyDict
if d["key"] is Key.X:
reveal_type(d["key"]) # note: Revealed type is 'Literal[Key.X]'
if d[KEY] is Key.X:
reveal_type(d[KEY]) # note: Revealed type is 'Literal[Key.X, Key.Y]'
Mypy is currently capable of narrowing expressions like d["key"], which we can see in the first expression.
So, it's natural to assume that mypy would be able to do the same for the second since the two programs are theoretically identical -- but we can't.
The root cause has to do with the "literal" subsystem (which is not to be confused with the Literal types subsystem) here: https://github.com/python/mypy/blob/master/mypy/literals.py#L65
The index in the second example is a NameExpr, which causes the if statement to evaluate to false and return a LITERAL_NO. This then makes the narrowing logic rule out d[KEY] as a candidate for narrowing in https://github.com/python/mypy/blob/master/mypy/checker.py#L3775.
I'm not really sure what the best way of fixing this would be. The natural solution would be to also pass along the expression type into the literal(...) function, but that seems very annoying to do. I'm also not entirely sure whether this is even a sound narrowing: I'm not very familiar with the "literals" subsystem, or how it's meant to interact with Literal types.
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
Issue の再現から始め、次に mypy/literals.py の literal() 周辺と、mypy/checker.py の 3775 行目付近にある narrowing ロジックを調べてください。KEY の NameExpr が LITERAL_NO を生成する理由を追跡し、直接の文字列インデックスと比較してください。KEY ケースで d[KEY] が d["key"] と一貫して Literal[Key.X] に絞り込まれれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- python
- 領域
- devtools
- issue の種類
- バグ
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 静か
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 48/100