Fix inaccurate `math.prod` Typing
This PR fixes the issues detailed in https://github.com/python/typeshed/issues/11913. One of the main strategies for accommodating the fact that an empty list inherently changes the result of the return-type, is having the first overloads be that of Iterable[Never], which will match an empty iterable first. Since the typing was fairly inaccurate before, I'm presuming a lot of repos will have new typing errors as a result of this change.
Let's walk through some examples (all with Pyright) of the new behavior:
Empty list will always evaluate to 1
res = math.prod([])
reveal_type(res) # Revealed type is Literal[1]
Given an empty list, but a start, the result will always be the type of the start:
res = math.prod([], start=Decimal(1))
reveal_type(res) # Revealed type is `Decimal`
Another example, where the list is filled out:
res = math.prod([Decimal(1)], start=Decimal(1))
reveal_type(res) # Revealed type is `Decimal`
With multiple types:
res = math.prod([Decimal(1), 1, 2.23], start=Decimal(1))
# Obviously this will actually be Decimal, but not sure we can get any better than this.
reveal_type(res) # Revealed type is Decimal | int | float
According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉
The test cases seem to work for Pyright, but have issues with MyPy since it seems MyPy doesn't match an empty list to list[Never], while Pyright does, for the overloading.
This is still not perfect, but it's probably the best we can do reasonably. Consider this code:
from decimal import Decimal
from math import prod
reveal_type(prod([Decimal(1), Decimal(2)], start=3.4))
Mypy says: note: Revealed type is "Union[typing.SupportsFloat, typing.SupportsIndex] (not error)
Runtime says: TypeError: unsupported operand type(s) for *: 'float' and 'decimal.Decimal
According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉