Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sum of an iterable of bools is considered to have a bool type #7579

Closed
lancelote opened this issue Apr 2, 2022 · 10 comments
Closed

Sum of an iterable of bools is considered to have a bool type #7579

lancelote opened this issue Apr 2, 2022 · 10 comments

Comments

@lancelote
Copy link
Contributor

Consider the following code

foo = sum([True, False])
foo += 1
  • mypy v0.931 is OK with it and reports foo type as int
  • mypy v0.940 warns
Incompatible types in assignment (expression has type "int", variable has type "Union[bool, Literal[0]]")

The stub does indeed state

@overload
def sum(__iterable: Iterable[_SumT]) -> _SumT | Literal[0]: ...

Though it is somewhat unfortunate. I've got beaten by this after updating mypy to the latest version.

@JelleZijlstra
Copy link
Member

See #7578 where we recently experimented with ways to address this sort of thing.

@ktbarrett
Copy link
Contributor

@JelleZijlstra I'm not sure how that's relevant. The problem is that bool + bool is int not bool. I think the only way to fix this is to add an overload for bool to return int.

@JelleZijlstra
Copy link
Member

@ktbarrett it's relevant because currently we assume that sum(Iterable[T]) returns T. We tried an alternative where we made sum return the return type of __add__ instead, but backed it out because it led to false positives.

Type checkers already understand that bool + bool returns an int.

@ktbarrett
Copy link
Contributor

Ah, I see the middle commit now. No one seemed to comment on the failure.

@jpy-git
Copy link
Contributor

jpy-git commented Apr 2, 2022

I think the reason this was passing in mypy 0.931 was that the return used to be typed as _T | int and has since been changed to _T | Literal[0] (the typevar change in #7578 won't have made it into mypy yet)
https://github.com/python/mypy/blob/4486d764c07a1cee9792d691e8e85cedfed2a451/mypy/typeshed/stdlib/builtins.pyi#L1389-L1393

That int in the return type would have been allowing foo += 1 but now it's been changed to Literal[0] (since I think it's intended to represent the default start value).

You can see an example here: https://mypy-play.net/?mypy=0.941&python=3.10&flags=strict&gist=4b96aaf8e1261db4bf484c0f76138638

pyright doesn't raise this error on the newer stubs so maybe mypy needs to be updated to account for this as well?
Alternatively, if the Literal[0] isn't providing any significant benefit, maybe it would just be simplest to revert Literal[0] to int?

@AlexWaygood
Copy link
Member

since I think it's intended to represent the default start value

Not quite. Literal[0] is there to represent the special case of the empty iterable being passed to sum.

>>> x: list[list[int]] = []
>>> sum(x)
0

@jpy-git
Copy link
Contributor

jpy-git commented Apr 2, 2022

yes because if you have an empty iterable you never add anything to the start value which is by default 0 😄

Help on built-in function sum in module builtins:

sum(iterable, /, start=0)
    Return the sum of a 'start' value (default: 0) plus an iterable of numbers

@AlexWaygood
Copy link
Member

yes because if you have an empty iterable you never add anything to the start value which is by default 0 😄

Sorry, looks like we were saying the same thing in different ways there 😄

@AlexWaygood
Copy link
Member

AlexWaygood commented Apr 2, 2022

pyright doesn't raise this error on the newer stubs so maybe mypy needs to be updated to account for this as well?

Yeah, there's some unfortunate disagreement among type checkers at the moment on how to treat literal types 😕 see #7258 for an extended discussion

But while the immediate cause of the new error might have been the change from int to Literal[0], I don't think that's really the underlying problem here.

@AlexWaygood
Copy link
Member

The specific case of bool + bool -> int has been fixed in #7975. The general case can't be solved without introducing a significant number of false-positive errors, as we saw when experimenting in #7578. As such, I'm closing this issue as as-fixed-as-it-can-be-for-now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants