mypy icon indicating copy to clipboard operation
mypy copied to clipboard

Class factory with `type[TypeVar]` with upper bound not checked correctly (false positive)

Open sterliakov opened this issue 2 years ago • 0 comments

Bug Report Class factory, that uses TypeVar with upper bound as a type, suffers from over-inference, thinking that type[SomeTypeVar] gives its upper bound on instantiation.

To Reproduce

from typing import TypeVar, Type, Union

class A:
    def __init__(self, x: str) -> None: pass
class B:
    def __init__(self, x: int) -> None: pass
class C:
    def __init__(self, x: int) -> None: pass

T = TypeVar('T', bound=Union[A, B])

def f(x: Type[T]) -> T:
    return x(1)  \
        # E: Incompatible return value type (got "Union[A, B]", expected "T") \
        # E: Argument 1 to "A" has incompatible type "int"; expected "str"

T2 = TypeVar('T2', bound=Union[B, C])

def f2(x: Type[T2]) -> T2:
    return x(1)  # E: Incompatible return value type (got "Union[B, C]", expected "T2")

Gist

Expected Behavior

I expect only 2nd error (invalid constructor arg) to be reported, without replacing a TypeVar with Union bound.

Actual Behavior

main.py:13: error: Incompatible return value type (got "Union[A, B]", expected "T")  [return-value]
main.py:13: error: Argument 1 to "A" has incompatible type "int"; expected "str"  [arg-type]
main.py:20: error: Incompatible return value type (got "Union[B, C]", expected "T2")  [return-value]
Found 3 errors in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 1.0.1 and master, repro's on older versions too
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.8-3.11 tested, irrelevant

sterliakov avatar Feb 26 '23 17:02 sterliakov