Skip to content

TypeVar incompatible with constrained union #9424

Description

@NeilGirdhar
fromtypingimportOptional, TypeVarU=TypeVar('U', bound=Optional[int])
deff(u: U) ->U:
ifuisNone:
returnNoneassertisinstance(u, int) # removing this line causes it to pass.returnu

Gives

main.py:10: error: Incompatible return value type (got "int", expected "U")

I cannot remove the assertion since it stands in for other code that is effectively constraining u.

This can be expressed tediously using overload:

fromtypingimportOptional, TypeVar, overload@overloaddeff(u: None) ->None: ...
@overloaddeff(u: int) ->int: ...
deff(u: Optional[int]) ->Optional[int]:
ifuisNone:
returnNoneassertisinstance(u, int)
returnu

Would it be possible to get the TypeVar approach to pass? It is far more succinct, and this quickly blows up in complexity if there are more argument-return type constraints to be enforced.

This pattern is analogous to the common class factory pattern:

classC: passclassB(C): passclassA(B): passT=TypeVar('T', bound=C)
deffactory(cls: Type[T]) ->T:
returncls()

Since A < B < C, this enforces

factory(Type[C]) -> C
factory(Type[B]) -> B
factory(Type[A]) -> A

This issue argues that since int < Optional[int] and None < Optional[int], we should ideally be able to similarly specify that

f(int) -> int
f(None) -> None

using the same notation.

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