python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.55k stars 2.84k forks source link

While loop prevents triggering "no return statement" #17014

Open sebsheep opened 8 months ago

sebsheep commented 8 months ago

Bug Report

A while loop in a function prevents mypy to detect a missing return statement.

To Reproduce https://mypy-play.net/?mypy=latest&python=3.12&flags=strict&gist=363627f969a9a127616dd5ee7ea2a235

def f() -> int:
    b = None
    while not b:
        b = 1

Expected Behavior

In strict mode, mypy should raise an error because f doesn't return Actual Behavior

Mypy successes!

Your Environment

KotlinIsland commented 8 months ago

More generally, the type of the while subject does not get updated from the body:

b = None
reveal_type(b)  # None from ? | None
while not b:
    reveal_type(b)  # None from ? | None
    b = 1
    reveal_type(b)  # int from int | None
reveal_type(b)  # unreachable

https://mypy-play.net/?mypy=basedmypy-latest&python=3.12&flags=strict&gist=363627f969a9a127616dd5ee7ea2a235

sebsheep commented 8 months ago

even if the while subject we had a true infinite loop, this function never returns... Is this the expected behavior?

def f() -> int:
    while True:
        pass

type checks!

KotlinIsland commented 8 months ago

Yes, that is intended, because it is technically correct, consider:

def f() -> Never:
    while True: ...

This doesn't produce any error because the function will Never return.

But perhaps it should warn here when the return type of the function is not Never, something like:

def f() -> int:
   while True:  # this loop will never return
       ...
davidhalter commented 3 months ago

@sebsheep I agree that this code should raise an error. Note however, that you have not enabled --warn-unreachable. I think it's a mistake that that's not enabled in --strict.

In your case that won't help. However it will help at least in

def f() -> int:
    while True:
        pass
    return 1