This came up in https://github.com/python/typeshed/pull/5067. In typeshed we have a few places where we assume that overloads are processed in definition order. For example: ``` @overload def foo(x: float) -> int: ... @overload def foo(x: object) -> str: ... reveal_type(foo(1.3)) # should be "int" ``` mypy warns about this case and must be silenced with "# type: ignore", but accepts it as do the other type checkers to my knowledge. I was surprised that this behavior is not described in either PEP 484 nor the typing docs. What can we do about this? I see the following options: * Clarify this behavior only in the typing docs. * Clarify this behavior both in the typing docs and in PEP 484. (My preferred option.) * Write a new PEP. * Do nothing. (Also I noticed that PEP 484 is still "Provisional".) - Sebastian
A few years ago Michael Lee redid much of the overload handling in mypy.
His specification is in
https://github.com/python/typing/issues/253#issuecomment-389262904; the
idea was to eventually turn it into a PEP, but evidently that never
happened.
El jue, 25 feb 2021 a las 3:45, Sebastian Rittau (
This came up in https://github.com/python/typeshed/pull/5067. In typeshed we have a few places where we assume that overloads are processed in definition order. For example:
``` @overload def foo(x: float) -> int: ... @overload def foo(x: object) -> str: ...
reveal_type(foo(1.3)) # should be "int" ```
mypy warns about this case and must be silenced with "# type: ignore", but accepts it as do the other type checkers to my knowledge. I was surprised that this behavior is not described in either PEP 484 nor the typing docs. What can we do about this?
I see the following options:
- Clarify this behavior only in the typing docs. - Clarify this behavior both in the typing docs and in PEP 484. (My preferred option.) - Write a new PEP. - Do nothing.
(Also I noticed that PEP 484 is still "Provisional".)
- Sebastian
_______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: jelle.zijlstra@gmail.com
For what it's worth, pytype also assumes the definition order matters.
("From narrow to broad", as it says in link Jelle posted.) I'm also very
surprised PEP 484 doesn't describe this behavior, because I'm sure I read
it there before.
-- Teddy
On Thu, Feb 25, 2021 at 7:00 AM Jelle Zijlstra
A few years ago Michael Lee redid much of the overload handling in mypy. His specification is in https://github.com/python/typing/issues/253#issuecomment-389262904; the idea was to eventually turn it into a PEP, but evidently that never happened.
El jue, 25 feb 2021 a las 3:45, Sebastian Rittau (
) escribió: This came up in https://github.com/python/typeshed/pull/5067. In typeshed we have a few places where we assume that overloads are processed in definition order. For example:
``` @overload def foo(x: float) -> int: ... @overload def foo(x: object) -> str: ...
reveal_type(foo(1.3)) # should be "int" ```
mypy warns about this case and must be silenced with "# type: ignore", but accepts it as do the other type checkers to my knowledge. I was surprised that this behavior is not described in either PEP 484 nor the typing docs. What can we do about this?
I see the following options:
- Clarify this behavior only in the typing docs. - Clarify this behavior both in the typing docs and in PEP 484. (My preferred option.) - Write a new PEP. - Do nothing.
(Also I noticed that PEP 484 is still "Provisional".)
- Sebastian
_______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: jelle.zijlstra@gmail.com
_______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: tsudol@google.com
Pyright also assumes that definition order matters and evaluates each overload in turn until it finds a match. Like mypy, pyright has a check for overlapping overloads whose return types do not match. It also reports when later overloads are "masked" by earlier overloads because their parameter lists and types overlap completely. I needed to [disable these checks](https://github.com/python/typeshed/blob/bf583da275014e07454369f4d4bf5cd91647...) when we recently added the pyright CI test for typeshed stubs because this error is reported in 13 places within typeshed. -- Eric Traut Contributor to Pyright & Pylance Microsoft Corp.
Am 25.02.21 um 21:14 schrieb Eric Traut:
Pyright also assumes that definition order matters and evaluates each overload in turn until it finds a match.
Like mypy, pyright has a check for overlapping overloads whose return types do not match. It also reports when later overloads are "masked" by earlier overloads because their parameter lists and types overlap completely. I needed to [disable these checks](https://github.com/python/typeshed/blob/bf583da275014e07454369f4d4bf5cd91647...) when we recently added the pyright CI test for typeshed stubs because this error is reported in 13 places within typeshed.
Could you clarify what you mean by "overlap completely"? The case that spawned this was typed like this: ``` _T = TypeVar("_T") @overload def foo(x: float) -> int: ... @overload def foo(x: _T) -> _T: ... ``` which should be fine and is necessary in some places. Of course the following: ``` _T = TypeVar("_T") @overload def foo(x: _T) -> _T: ... @overload def foo(x: float) -> int: ... ``` is definitely an error we should fix in typeshed, because the second overload doesn't do anything. We already need to add `# type: ignore`s for mypy's benefit, so we can do the same for pyright and enable `reportOverlappingOverload`. Although ideally, mypy and pyright would recognize "partial" overrides like in the first case and not issue warnings. - Sebastian
It looks like there are some difference between mypy and pyright with respect to the overload cases they flag as errors. I'll try to make pyright match mypy's behavior so they're consistent. ```python # pyright: strict from typing import Literal, TypeVar, Union, overload @overload def foo1(x: int) -> int: ... @overload def foo1(x: float) -> int: ... # Mypy: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader # Pyright: Overload 2 for "foo2" will never be used because its parameters overlap overload 1 @overload def foo2(x: float) -> int: ... @overload def foo2(x: int) -> int: ... # Mypy: Overloaded function signatures 1 and 2 overlap with incompatible return types # Pyright: Overload 1 for "foo3" overlaps overload 2 and returns an incompatible type @overload def foo3(x: Literal[3]) -> int: ... @overload def foo3(x: int) -> str: ... # Mypy: No error # Pyright: Overload 1 for "foo4" overlaps overload 2 and returns an incompatible type @overload def foo4(x: int) -> int: ... @overload def foo4(x: float) -> str: ... # Mypy: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader # Pyright: No error _T = TypeVar("_T") @overload def foo5(x: _T) -> Union[int, _T]: ... @overload def foo5(x: int) -> str: ... ```
participants (4)
-
Eric Traut
-
Jelle Zijlstra
-
Sebastian Rittau
-
Teddy Sudol