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
{{ message }}
Repository navigation
bool/float treated inconsistently with bool/int and int/float, causing inconsistent Union simplification #1850
l = [] # type: List[Union[bool, int, float]]
causes "error: Incompatible types in assignment (expression has type List[float], variable has type List[Union[bool, int, float]])"
I looked into this because I thought it might have been something I broke. Technically it was exposed by one of my changes, but the underlying issue is older. mypy thinks that bool is a subtype of int, and that int is a subtype of float, but that bool isn't a subtype of float. That's ultimately the reason that you only see this behavior when all three types are involved.
I think maybe the right thing to do here is copy a class's _promote attribute into its derived classes? Not sure.
Not really bugs, but also contributing to make this issue visible are:
mypy doesn't internally simplify unions that appear in type comments. It seems like it might as well; any reason not to?
apply_generic_arguments could exit early when the list of arguments to apply is empty, saving a traversal of the callable type. (What happened here is that expand_type simplified the union, but then it was no longer equivalent to the original, because of the bug that bool is not considered a subtype of float.)
Mypy should probably simplify all unions that are used internally. Having non-simplified unions is problematic, as parts of mypy likely assume that everything is simplified. I'm not sure whether we have enough information to perform simplification when doing semantic analysis of types, as this requires a full MRO and well-formed types -- we may have to do it on demand when we read types during type checking.
Simplifying annotations might be a little unintuitive for users, as an annotation like Union[bool, int] would get turned into just int. Perhaps mypy could give a warning if a type annotation has a union type that can be simplified? However, users may want to give redundant information in unions for documentation purposes, so even this might not be a good option. At least making it clear in the documentation how this works sounds like a good idea.
changed the title [-]Inconsistent Union simplification[/-][+]bool/float treated inconsistently with bool/int and int/float, causing inconsistent Union simplification[/+]on Jul 14, 2016
mypy can't even infer the proper return type if the annotation is as simple as -> bool | int. It always returns the return type as an int, even though the actual return value is clearly a bool (in my case it was the value of False). Until this day, I wasn't able to understand why mypy can't infer a bool if the return type is a union bool | int.
Activity
rwbarton commentedon Jul 13, 2016
I looked into this because I thought it might have been something I broke. Technically it was exposed by one of my changes, but the underlying issue is older. mypy thinks that
boolis a subtype ofint, and thatintis a subtype offloat, but thatboolisn't a subtype offloat. That's ultimately the reason that you only see this behavior when all three types are involved.I think maybe the right thing to do here is copy a class's
_promoteattribute into its derived classes? Not sure.Not really bugs, but also contributing to make this issue visible are:
apply_generic_argumentscould exit early when the list of arguments to apply is empty, saving a traversal of the callable type. (What happened here is thatexpand_typesimplified the union, but then it was no longer equivalent to the original, because of the bug thatboolis not considered a subtype offloat.)JukkaL commentedon Jul 13, 2016
Mypy should probably simplify all unions that are used internally. Having non-simplified unions is problematic, as parts of mypy likely assume that everything is simplified. I'm not sure whether we have enough information to perform simplification when doing semantic analysis of types, as this requires a full MRO and well-formed types -- we may have to do it on demand when we read types during type checking.
Simplifying annotations might be a little unintuitive for users, as an annotation like
Union[bool, int]would get turned into justint. Perhaps mypy could give a warning if a type annotation has a union type that can be simplified? However, users may want to give redundant information in unions for documentation purposes, so even this might not be a good option. At least making it clear in the documentation how this works sounds like a good idea.gvanrossum commentedon Jul 13, 2016
I recall a discussion with @ddfisher where he was against always simplifying unions. (I can't find the specific issue -- maybe it was IRL. :-)
ddfisher commentedon Jul 14, 2016
I thought it was just that there was some bug with union simplification that was problematic?
rwbarton commentedon Jul 14, 2016
In any case, not simplifying unions should generally be harmless. The real issue here is that
boolis not considered a subtype offloat.ddfisher commentedon Jul 14, 2016
I think this is a decent example of where a fully fleshed-out formalism for mypy would be useful.
[-]Inconsistent Union simplification[/-][+]bool/float treated inconsistently with bool/int and int/float, causing inconsistent Union simplification[/+]gnprice commentedon Jul 14, 2016
I've retitled the issue to reflect Reid's observation.
Make is_subtype and is_proper_subtype do promotion the same way
PedanticHacker commentedon Dec 20, 2022
mypy can't even infer the proper return type if the annotation is as simple as
-> bool | int. It always returns the return type as anint, even though the actual return value is clearly abool(in my case it was the value ofFalse). Until this day, I wasn't able to understand why mypy can't infer aboolif the return type is a unionbool | int.hauntsaninja commentedon Dec 20, 2022
bool is a subclass of int, so bool is an int. In what way do you expect a return type of
bool | intto be different fromint?