Skip to content

Treat widening type variables consistently #18456

Open
@A5rocks

Description

@A5rocks

Bug Report

Currently, mypy allows widening type variables without an error, then errors (sometimes, see below) at usage time. This seems backwards to me. I'm opening this based on a minimization from @sterliakov in #18451.

To Reproduce

There's several interesting snippets:

import typing

IntT = typing.TypeVar("IntT", bound=int)
StrT = typing.TypeVar("StrT", bound=str)
AnyT = typing.TypeVar("AnyT", bound=typing.Any)

class IntC(typing.Generic[IntT]): ...
class StrC(typing.Generic[StrT]): ...

AnyC = IntC[AnyT] | StrC[AnyT]

def run(_: AnyC[StrT]) -> StrT: ...  # E: Type argument "StrT" of "IntC" must be a subtype of "int"

In this case, I would expect an error on the AnyC type alias definition, and maybe at usage time. What about other methods of widening type variables?

import typing

IntT = typing.TypeVar("IntT", bound=int)
StrT = typing.TypeVar("StrT", bound=str)
AnyT = typing.TypeVar("AnyT", bound=typing.Any)

class IntC(typing.Generic[IntT]): ...

class AnyC(IntC[AnyT]):  # ! no error
    pass

def f(x: StrT) -> StrT:
    y: AnyC[StrT]  # !? no error
    return x

This version doesn't error at all! What I would expect is the behavior achieved by using object plus a class to widen:

import typing

IntT = typing.TypeVar("IntT", bound=int)
StrT = typing.TypeVar("StrT", bound=str)
AnyT = typing.TypeVar("AnyT", bound=object)

class IntC(typing.Generic[IntT]): ...
class StrC(typing.Generic[StrT]): ...

class AnyC1(IntC[AnyT]):  # E: Type argument "AnyT" of "IntC" must be a subtype of "int"  
    pass

AnyC2 = IntC[AnyT] | StrC[AnyT]  # ! no error

def f(x: StrT) -> StrT:
    y1: AnyC1[StrT]  # no error, this is fine
    y2: AnyC2[StrT]  # E: Type argument "StrT" of "IntC" must be a subtype of "int"
    return x

Expected Behavior

Consistency.

Actual Behavior

To summarize the above

method of widening bound=object bound=Any
type alias usage error usage error
class definition error no errors (!)

Your Environment

Everything was double checked in mypy playground.

  • Mypy version used: v1.14.1
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): N/A
  • Python version used: 3.12

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