Skip to content

Wrong revealed type of float/int multiplied/divided by sum(Iterable[complex]). #6040

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

Closed
AndrewUshakov opened this issue Dec 9, 2018 · 5 comments
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal topic-type-variables

Comments

@AndrewUshakov
Copy link

For the code below (Python 3.7.1) mypy 0.650 improperly reveals types of expressions: (float/int multiplied/divided by the sum(arg)), where arg is Iterable[complex] and generates false positive errors for the type of the first argument of the sum (they are in comments). Attempt to explicitly define 'start' parameter does not help. There are no problems with locally defined function f2 with similar signature.

Additional question is: what does mean '' in "Revealed type is 'builtins.complex'" in the line 13?

from typing import Iterable, TYPE_CHECKING, TypeVar

_TC = TypeVar('_TC', int, float, complex)


def f1(arg: Iterable[complex]) -> complex:
    if TYPE_CHECKING:

        reveal_type(f2(arg))                # Revealed type is 'builtins.complex' Ok.
        reveal_type(1/f2(arg))              # Revealed type is 'builtins.complex' Ok.
        reveal_type(1*f2(arg))              # Revealed type is 'builtins.complex' Ok.

        reveal_type(sum(arg))               # Revealed type is 'builtins.complex*' <- What does mean '*' at the end?

        reveal_type(1/sum(arg))             # Revealed type is 'builtins.float' ???
                                            # Argument 1 to "sum" has incompatible type "Iterable[complex]"; expected "Iterable[int]" ???

        reveal_type(1*sum(arg))             # Revealed type is 'builtins.int' ???
                                            # Argument 1 to "sum" has incompatible type "Iterable[complex]"; expected "Iterable[int]" ???

        reveal_type(1.0/sum(arg))           # Revealed type is 'builtins.float' ???
                                            # Argument 1 to "sum" has incompatible type "Iterable[complex]"; expected "Iterable[float]" ???

        reveal_type(1.0*sum(arg))           # Revealed type is 'builtins.float' ???
                                            # Argument 1 to "sum" has incompatible type "Iterable[complex]"; expected "Iterable[float]" ???

        reveal_type(1/sum(arg, start=complex(0.0)))  # Revealed type is 'builtins.float' ???
                                            # Argument 1 to "sum" has incompatible type "Iterable[complex]"; expected "Iterable[int]" ???

        reveal_type(complex(1)/sum(arg))    # Revealed type is 'builtins.complex' <- workaround
        reveal_type(1/complex(sum(arg)))    # Revealed type is 'builtins.complex' <- workaround

    return 1/sum(arg)                       # error: Argument 1 to "sum" has incompatible type "Iterable[complex]"; expected "Iterable[int]"


def f2(arg: Iterable[_TC]) -> _TC:
    return 1/next(iter(arg))


if __name__ == '__main__':

    a = [1.0, 2.0+3.0j]
    print(f1(a))
@JelleZijlstra
Copy link
Member

The * means it's an inferred type, not an explicitly specified type. It doesn't really matter unless you're interested in mypy internals.

@ilevkivskyi
Copy link
Member

This is another example of the situation where mypy is too eager about return/outer type context. Mypy uses the external context first, in particular, in this example int.__mul__ annotated as (int) -> int, sets the int context for sum(...), so the type variable _T is inferred as int. Therefor you see a weird error like "Iterable[int]" expected. Since this is a well known problem, mypy special-cases functions that return a plain type variable (like f2() in your example). But the crux is that sum() is annotated in typeshed as returning Union[_T, int], so that special-casing doesn't apply to it, and you see the bug.

Possible short term solution is to annotate sum() as just returning _T, but the only long term solution is to use "single bin inference".

See also #5971

@ilevkivskyi ilevkivskyi added bug mypy got something wrong topic-type-variables priority-1-normal false-positive mypy gave an error on correct code labels Dec 9, 2018
BobbyRBruce pushed a commit to gem5/gem5 that referenced this issue Apr 2, 2021
This fixes some errors and warning when running mypy.

`gem5/src/python/m5/ext> mypy pystats`

There is one error that is ignored, which is a bug in mypy. See
python/mypy#6040

Change-Id: I18b648c059da12bd30d612f0e265930b976f22b4
Signed-off-by: Jason Lowe-Power <[email protected]>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/42644
Reviewed-by: Andreas Sandberg <[email protected]>
Maintainer: Bobby R. Bruce <[email protected]>
Tested-by: kokoro <[email protected]>
@arthurazs
Copy link

Possible short term solution is to annotate sum() as just returning _T, but the only long term solution is to use "single bin inference".

How would I go about annotating sum()?
Cheers

@hynekcer
Copy link

This issue can be closed.

Everything about sum(...) works in the example above with the mypy 0.960 while a version 0.950 still was with same errors.

The only reported error remains in the function f2() but it is an incorrectly typed function, because 1 / 1 is a float not an int. If the the "int" is removed from the second line: _TC = TypeVar('_TC', float, complex) then everything works also with int, float and complex:

reveal_type(f2([1]))  # Revealed type is "builtins.float"

@hynekcer
Copy link

@hauntsaninja This issue can be closed similarly to #8814 that you closed yesterday.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal topic-type-variables
Projects
None yet
Development

No branches or pull requests

6 participants