python / python/mypy

Inferred attribute type feeds back as call context, rejecting its own defining assignment

オープン
#21,809 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

bug
主要言語
Python
スター
20.6k
フォーク
3.3k
PR マージ指標
PR 指標を取得中

説明

Bug Report

Assigning a generic call returning K | None to a previously undeclared
self. attribute spuriously fails [arg-type] on that same assignment. The
attribute's inferred type (str | None) apparently comes back as call context
on a later pass, solving K = str | None; the invariant Mapping key then
rejects dict[str, str].

The same expression passes with no context, an annotated local, an annotated
attribute, or a reassigned local (whose second assignment is likewise checked
against its own inferred str | None) — the optional-stripping special case
seems skipped on the inferred-attribute path alone. A sync version (no
async/await) also passes, pointing at the deferred re-check await
triggers.

To Reproduce

from collections.abc import Mapping


async def select_one[K](options: Mapping[K, str]) -> K | None: ...


class ViaInferredAttr:
    async def m(self) -> None:
        cases = {"a": "x"}
        self._done = await select_one(cases)  # error (spurious)


async def via_local() -> None:
    cases = {"a": "x"}
    done = await select_one(cases)  # ok
    done = await select_one(cases)  # ok (context = inferred str | None)
    done2: str | None = await select_one(cases)  # ok


class ViaAnnotatedAttr:
    _done: str | None

    async def m(self) -> None:
        cases = {"a": "x"}
        self._done = await select_one(cases)  # ok

Expected Behavior

All call sites typecheck, with K = str.

Actual Behavior

repro.py:10: error: Argument 1 to "select_one" has incompatible type "dict[str, str]"; expected "Mapping[str | None, str]"  [arg-type]

The str | None key shows the return's | None leaked into K.

Your Environment

  • mypy 1.20.2 (compiled), no flags
  • Python 3.13

Related: #5874 (over-eager outer context with unions), #19304 (assignment target
changes results). New here: the context is self-inferred — no annotation exists
anywhere — and explicit spellings of the same type behave differently.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

issue の再現コードから始め、宣言されていない self 属性への代入に対する遅延非同期再チェックを追跡します。その経路を、正常に通過するローカル属性およびアノテーション付き属性のケースと比較し、推論された戻り値コンテキストがジェネリック引数の推論にどのように到達するかに注目します。K が str として推論されて再現コードが通り、回帰テストでこの動作がカバーされれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
python
領域
compilers
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
静か
明瞭さ
おおむね明確
初心者へのやさしさ
48/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。