pyright icon indicating copy to clipboard operation
pyright copied to clipboard

False Positive of `reportUnnecessaryComparison` for Loop Variables

Open ckwastra opened this issue 9 months ago • 3 comments

Describe the bug & Code or Screenshots In the following code, the loop condition i != 10 is flagged by Pyright, while j != 10 is accepted, even though both loops implement the same logic (PP):

def test() -> bool: ...

i = 0
while i != 10:  # Pyright: Condition will always evaluate to True since the types "Literal[0]" and "Literal[10]" have no overlap
    if test():
        continue
    i += 1

j = 0
while j != 10:
    if test():
        continue
    j += 1

VS Code extension or command-line Pylance version: 2025.4.100

ckwastra avatar Apr 13 '25 15:04 ckwastra

Thanks for the bug report and the clean, simple repro case. I have some theories about the underlying cause, but I'll need to investigate further.

erictraut avatar Apr 14 '25 01:04 erictraut

Another related—albeit somewhat contrived—example is shown below (PP):

i = 0

def work() -> None:
    global i
    print(i)
    i += 1

while i != 10:  # Pyright: Condition will always evaluate to True since the types "Literal[0]" and "Literal[10]" have no overlap
    work()

Interestingly, I found that replacing i = 0 with i = int(0) resolves the issue.

ckwastra avatar Apr 14 '25 05:04 ckwastra

The second example is working as intended, so I don't consider that a bug. Pyright performs type narrowing locally within an execution scope without regard for side effects that may occur in other execution scopes. Static type checkers cannot generally determine if and when code within other scopes may be executed. If you want your code to work well with static analyzers, avoid writing code that has side effects like this.

erictraut avatar Apr 14 '25 05:04 erictraut