You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It appears that if a function returns a union of type variables, how mypy chooses to assign/unify those type variables changes if a call happens in a location that has an explicit type (e.g. assigned to a variable with an annotation or in a direct return f(...) call within a function that has a return type hint).
In particular, it appears both type variables end up being unified to that explicit hint, rather than to individual components of the hint's union (for instance, in the reproducer below, it seems that it chooses _T1 = _T2 = int | str, but "should" be _T1 = int and _T2 = str).
This is observable when those parameters are used in contravariant position in an argument, such as the parameters of functions, and can result in some seemingly spurious errors.
(I tried searching for existing discussion/bugs and didn't find any, but I may not have found the exactly correct terms.)
Here's another case which I think is caused by the same underlying issue:
fromtypingimportTypeVarDT=TypeVar('DT')
defgetstr(default: DT|None=None) ->str|DT:
assertFalse# That's finereveal_type(getstr()) # Revealed type is "builtins.str"z=None# Unexpectedly brokenreveal_type(zorgetstr()) # Revealed type is "Union[builtins.str, None]"# But oddly, that way works finereveal_type(zifzelsegetstr()) # Revealed type is "builtins.str"
Bug Report
It appears that if a function returns a union of type variables, how mypy chooses to assign/unify those type variables changes if a call happens in a location that has an explicit type (e.g. assigned to a variable with an annotation or in a direct
return f(...)
call within a function that has a return type hint).In particular, it appears both type variables end up being unified to that explicit hint, rather than to individual components of the hint's union (for instance, in the reproducer below, it seems that it chooses
_T1 = _T2 = int | str
, but "should" be_T1 = int
and_T2 = str
).This is observable when those parameters are used in contravariant position in an argument, such as the parameters of functions, and can result in some seemingly spurious errors.
(I tried searching for existing discussion/bugs and didn't find any, but I may not have found the exactly correct terms.)
To Reproduce
Reduced example (i.e. not relying on typeshed's hints): https://mypy-play.net/?mypy=latest&python=3.12&gist=697d00f7b3a089d7e56f6d86ec5193e8
This happens in practice with functions like
min
with the interaction between thekey
functions anddefault
: https://mypy-play.net/?mypy=latest&python=3.12&gist=7f892a21b5d3d1db89419620e3cedf47Expected Behavior
Both the
broken
andworks
code should behave the same, and in particular, they should both work.Actual Behavior
Your Environment
mypy.ini
(and other config files): n/aThe text was updated successfully, but these errors were encountered: