Inferred attribute type feeds back as call context, rejecting its own defining assignment
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 20.6k
- Forks
- 3.3k
- PR merge metrics
- PR metrics pending
Description
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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the reproducer in the issue and trace the deferred async re-check for an assignment to an undeclared self attribute. Compare that path with the passing local and annotated-attribute cases, focusing on how inferred return context reaches generic argument inference. Done means the reproducer passes with K inferred as str and a regression test covers the behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100