Skip to content

bool/float treated inconsistently with bool/int and int/float, causing inconsistent Union simplification #1850

Closed

Description

@ajprax

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 also tried

l1 = [] # type: List[Union[bool, int]]
l2 = [] # type: List[Union[bool, float]]
l3 = [] # type: List[Union[int, float]]
x = True # type: Union[bool, int, float]

and they all pass.

Activity

  1. rwbarton commented on Jul 13, 2016

    @rwbarton
    Contributor

    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.)
  2. JukkaL commented on Jul 13, 2016

    @JukkaL
    Collaborator

    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.

  3. gvanrossum commented on Jul 13, 2016

    @gvanrossum
    Member

    I recall a discussion with @ddfisher where he was against always simplifying unions. (I can't find the specific issue -- maybe it was IRL. :-)

  4. ddfisher commented on Jul 14, 2016

    @ddfisher
    Collaborator

    I thought it was just that there was some bug with union simplification that was problematic?

  5. rwbarton commented on Jul 14, 2016

    @rwbarton
    Contributor

    In any case, not simplifying unions should generally be harmless. The real issue here is that bool is not considered a subtype of float.

  6. ddfisher commented on Jul 14, 2016

    @ddfisher
    Collaborator

    I think this is a decent example of where a fully fleshed-out formalism for mypy would be useful.

  7. changed the title [-]Inconsistent Union simplification[/-] [+]bool/float treated inconsistently with bool/int and int/float, causing inconsistent Union simplification[/+] on Jul 14, 2016
  8. gnprice commented on Jul 14, 2016

    @gnprice
    Collaborator

    I've retitled the issue to reflect Reid's observation.

  9. added this to the milestone on Jul 14, 2016
  10. removed this from the milestone on Mar 29, 2017
  11. added a commit that references this issue on Mar 31, 2017
    6f9ff36
  12. PedanticHacker commented on Dec 20, 2022

    @PedanticHacker

    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.

  13. hauntsaninja commented on Dec 20, 2022

    @hauntsaninja
    Collaborator

    bool is a subclass of int, so bool is an int. In what way do you expect a return type of bool | int to be different from int?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions