Skip to content

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

Open

Description

@Kache

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.

Activity

  1. added
    bugmypy got something wrong
    on Aug 4, 2026
  2. rheard commented on Aug 6, 2026

    @rheard
    Contributor

    Hello @Kache , thank you for the bug report.

    I have added a unit test reproducing this particular usecase to my PR for #19304 here. I have confirmed the test fails in master but passes with the fixes found in the PR.

    Have a great day,
    Ryan.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrong

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions