KEMBAR78
mypy incorrectly tags function argument TypeVar with return type when called from a caller with the same signature · Issue #16924 · python/mypy · GitHub
Skip to content

mypy incorrectly tags function argument TypeVar with return type when called from a caller with the same signature #16924

@satyanash

Description

@satyanash

Bug Report

mypy incorrectly tags a function argument of type Mapping[K, V] where K and V are TypeVar with the return value of the caller function.

To Reproduce

The below small program demonstrates the issue:

from typing import Dict, Mapping, TypeVar, Union

K = TypeVar("K")
V = TypeVar("V")
K2 = TypeVar("K2")
V2 = TypeVar("V2")

def func(one: Dict[K, V], two: Mapping[K2, V2]) -> Dict[Union[K, K2], Union[V, V2]]:
    reveal_type(one)
    reveal_type(two)
    return {}

def caller(arg1: Mapping[K, V], arg2: Mapping[K2, V2]) -> Dict[Union[K, K2], Union[V, V2]]:
    reveal_type(arg1)
    reveal_type(arg2)
    _arg1 = arg1 if isinstance(arg1, dict) else dict(arg1)
    return func(_arg1, arg2)

Expected Behavior

mypy should succeed without an error.

$ mypy --strict break_mypy.py
break_mypy.py:10: note: Revealed type is "builtins.dict[K`-1, V`-2]"
break_mypy.py:11: note: Revealed type is "typing.Mapping[K2`-3, V2`-4]"
break_mypy.py:16: note: Revealed type is "typing.Mapping[K`-1, V`-2]"
break_mypy.py:17: note: Revealed type is "typing.Mapping[K2`-3, V2`-4]"
Success: no issues found in 1 source file

Actual Behavior

mypy complains with a very weird error, even though the revealed types are correct

$ mypy --strict break_mypy.py
break_mypy.py:10: note: Revealed type is "builtins.dict[K`-1, V`-2]"
break_mypy.py:11: note: Revealed type is "typing.Mapping[K2`-3, V2`-4]"
break_mypy.py:16: note: Revealed type is "typing.Mapping[K`-1, V`-2]"
break_mypy.py:17: note: Revealed type is "typing.Mapping[K2`-3, V2`-4]"
break_mypy.py:19: error: Argument 2 to "func" has incompatible type "Mapping[K2, V2]"; expected "Mapping[Union[K, K2], Union[V, V2]]"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

More Info

Note, if I change the type signature of the caller, it ends up changing the type signature of the called function as well:

from typing import Dict, Mapping, TypeVar, Union

K = TypeVar("K")
V = TypeVar("V")
K2 = TypeVar("K2")
V2 = TypeVar("V2")


def func(one: Dict[K, V], two: Mapping[K2, V2]) -> Dict[Union[K, K2], Union[V, V2]]:
    reveal_type(one)
    reveal_type(two)
    return {}


def caller(arg1: Mapping[K, V], arg2: Mapping[K2, V2]) -> None:
    reveal_type(arg1)
    reveal_type(arg2)
    _arg1 = arg1 if isinstance(arg1, dict) else dict(arg1)
    func(_arg1, arg2)

will return:

$ mypy --strict break_mypy.py
break_mypy.py:10: note: Revealed type is "builtins.dict[K`-1, V`-2]"
break_mypy.py:11: note: Revealed type is "typing.Mapping[K2`-3, V2`-4]"
break_mypy.py:16: note: Revealed type is "typing.Mapping[K`-1, V`-2]"
break_mypy.py:17: note: Revealed type is "typing.Mapping[K2`-3, V2`-4]"
Success: no issues found in 1 source file

Your Environment

  • Mypy version used: mypy 0.991 (compiled: yes)
  • Mypy command-line flags: --strict
  • Mypy configuration options from mypy.ini (and other config files):
    ignore_missing_imports = true
    
  • Mypy plugins: sqlalchemy.ext.mypy.plugin, pydantic.mypy and numpy.typing.mypy_plugin
  • Python version used: Python 3.9.17

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