mypy icon indicating copy to clipboard operation
mypy copied to clipboard

sys.exit() is not considered as noreturn

Open socketpair opened this issue 1 year ago • 14 comments

https://mypy-play.net/?mypy=latest&python=3.10&flags=strict%2Cstrict-equality&gist=e86aa52c05acd36b6c04067cb6f44ce1

import sys

def main() -> int:
    return sys.exit(42)

MyPy finds nothing wrong here.

Anyway, this should be valid:

try:
    sys.exit(42)
except SystemExit:
    print('xxx') # this line IS reachable.

i.e. this function either raises specific exception or noreturn.

socketpair avatar Sep 02 '22 09:09 socketpair

Can you clarify what you think the bug is? Mypy is correct when it doesn't produce any errors on your first sample, because a function that never returns is a valid Callable[[], int].

JelleZijlstra avatar Sep 02 '22 19:09 JelleZijlstra

Looks like sys.exit is indeed recognised as returning NoReturn: https://mypy-play.net/?mypy=latest&python=3.10&flags=strict%2Cstrict-equality%2Cwarn-unreachable&gist=ef39ea5ba16960f2dd4274349a2c142d

So, it looks fine to me!

sobolevn avatar Sep 02 '22 21:09 sobolevn

Using return value of noreturn function is an error, indeed.

socketpair avatar Sep 02 '22 22:09 socketpair

Feel free to reopen if you have other questions / problems :)

sobolevn avatar Sep 03 '22 09:09 sobolevn

@sobolevn please reopen. It's not fixed actually.

socketpair avatar Sep 04 '22 04:09 socketpair

Can you please specify what example is not fixed?

sobolevn avatar Sep 04 '22 08:09 sobolevn

The first one. Mypy does not see any errors in using value of noreturn function.

socketpair avatar Sep 04 '22 20:09 socketpair

The first code sample is not a bug. Mypy is correct in not emitting an error here. NoReturn (which is equivalent to the recently-introduced typing.Never type) is a bottom type in the Python type system, and it is is compatible with all other types. A return value of type NoReturn is compatible with the declared return type int.

erictraut avatar Sep 04 '22 21:09 erictraut

I think, Noreturn must not be compatible with any other type. What the case when it should be compatible ?

socketpair avatar Sep 05 '22 02:09 socketpair

Should be def sys.exit(arg: int) -> Never. Does not it ? That is the same as -> NoReturn here. Both must be incompatible with any other type, like int.

socketpair avatar Sep 05 '22 02:09 socketpair

NoReturn is another name for Never. It is the "bottom type" in Python type system. You can think of it as equivalent to an empty union. NoReturn is compatible with all other types. No other type (other than NoReturn itself) is compatible with NoReturn.

erictraut avatar Sep 05 '22 03:09 erictraut

Thanks for verbose explanation. I checked TypeScript:

const sys_exit: (code: number) => never = (code: number) => {
    throw new Error('message');
};

const x: number = sys_exit(42);

It also sees nothing wrong here.

image

I still don't understand why NoReturn / Never should be compatible with all types. For me, it must not by definition. Seems I don't understand something important in typing system. Will be great if you provide a link.

socketpair avatar Sep 06 '22 04:09 socketpair

Because a value of Never can not exist, it is safe to use as a value of any type.

https://en.wikipedia.org/wiki/Bottom_type

def n() -> Never: raise Exception

print(n() + 1)

At runtime, this will not produce a TypeError, because the + will never be executed.

KotlinIsland avatar Sep 07 '22 02:09 KotlinIsland

Why not make it incompatible with any type to detect obvious errors such as trying to use return value of noreturn functions ?

socketpair avatar Sep 07 '22 03:09 socketpair