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

False positive unreachable with redefined variable in loop #8865

Closed
mthuurne opened this issue May 20, 2020 · 4 comments · Fixed by #18433
Closed

False positive unreachable with redefined variable in loop #8865

mthuurne opened this issue May 20, 2020 · 4 comments · Fixed by #18433
Labels
bug mypy got something wrong topic-reachability Detecting unreachable code topic-type-narrowing Conditional type narrowing / binder

Comments

@mthuurne
Copy link
Contributor

When checking the following code:

from typing import AbstractSet, Iterable, Optional, Set, TypeVar

T = TypeVar('T')

def intersection(seq: Iterable[AbstractSet[T]]) -> Optional[Set[T]]:
    ret = None
    for elem in seq:
        if ret is None:
            ret = set(elem)
        else:
            ret &= elem
    return ret

mypy reports:

$ mypy --warn-unreachable intersection.py
intersection.py:11: error: Statement is unreachable

This statement is the ret &= elem inside the else block.

It seems that mypy is using the initial type of ret to conclude that ret is None is always true, ignoring the fact that inside the loop ret is redefined to a different type.

If I place a reveal_type just before the return, mypy does report Union[builtins.set[T`-1], None] as the type, so it figures out the redefinition eventually.

I'm using mypy 0.770 on Pyton 3.8.2, with the --warn-unreachable flag.

mthuurne added a commit to boxingbeetle/softfab that referenced this issue May 21, 2020
The loop is unrolled one cycle, so we can initialize `ret` to a set
from the start. Besides helping mypy, it is also a bit more efficient.

python/mypy#8865
@beezee
Copy link
Contributor

beezee commented May 22, 2020

Does ret: Optional[Set] = None clear the error?

@mthuurne
Copy link
Contributor Author

Yes, which is further evidence that the problem is in the order in which mypy does things: it seems to flag the code as unreachable before the final type for ret has been deduced.

@sbalmer
Copy link

sbalmer commented Mar 9, 2021

I stumbled over this and created a minimal example:

maximum = None
for x in [2, 1]:
    if maximum is None:
        maximum = x
    else:
        maximum = max(x, "maximum")

The last line contains an error. The variable maximum should be passed, but instead, the string "maximum" is passed. Mypy does not detect this because it assumes the last line is unreachable.

Tested with Mypy 0.812 on Python 3.6.9.

@mthuurne
Copy link
Contributor Author

mthuurne commented Feb 7, 2024

I've got a slightly more minimal test case for what I think is the same problem:

def check_sorted(items: list[int]) -> None:
    prev = None
    for item in items:
        reveal_type(prev)
        assert prev is None or prev <= item
        prev = item
    reveal_type(prev)

Output of mypy 1.8.0:

testcase.py:4: note: Revealed type is "None"
testcase.py:5: error: Right operand of "or" is never evaluated  [unreachable]
            assert prev is None or prev <= item
                                   ^~~~~~~~~~~~
testcase.py:7: note: Revealed type is "Union[builtins.int, None]"

Expected output:

testcase.py:4: note: Revealed type is "Union[builtins.int, None]"
testcase.py:7: note: Revealed type is "Union[builtins.int, None]"

It seems mypy is able to correctly infer the type of prev after the loop (line 7), but doesn't feed this back into the start of the loop body (line 4).

@hauntsaninja hauntsaninja added the topic-type-narrowing Conditional type narrowing / binder label Nov 18, 2024
tyralla added a commit to tyralla/mypy that referenced this issue Jan 9, 2025
Fixes python#18348
Fixes python#13973
Fixes python#11612
Fixes python#8721
Fixes python#8865
Fixes python#7204

I manually checked all the listed issues.  Some of them were already partly fixed by python#18180.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-reachability Detecting unreachable code topic-type-narrowing Conditional type narrowing / binder
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants