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

Re-work overload overlap logic #17392

Merged
merged 13 commits into from
Jun 19, 2024
Merged
Prev Previous commit
Next Next commit
Update tests
  • Loading branch information
ilevkivskyi committed Jun 17, 2024
commit 5ee882637aaa6dd624ac23e1549a2c30ec7c3239
8 changes: 7 additions & 1 deletion test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -4005,10 +4005,16 @@ def f(a: Type[User]) -> int: pass # E: Overloaded function signatures 1 and 2 o
@overload
def f(a: object) -> str: pass

# Note: plain type is equivalent to Type[Any] so no error here
@overload
def g(a: Type[User]) -> int: pass # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def g(a: Type[User]) -> int: pass
@overload
def g(a: type) -> str: pass

@overload
def h(a: Type[User]) -> int: pass # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
@overload
def h(a: Type[object]) -> str: pass
[builtins fixtures/classmethod.pyi]
[out]

Expand Down
67 changes: 36 additions & 31 deletions test-data/unit/check-overloading.test
Original file line number Diff line number Diff line change
Expand Up @@ -1325,8 +1325,9 @@ def h(x: Sequence[str]) -> int: pass
@overload
def h(x: Sequence[T]) -> None: pass # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader

# Safety of this highly depends on the implementation, so we lean towards being silent.
@overload
def i(x: List[str]) -> int: pass # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def i(x: List[str]) -> int: pass
@overload
def i(x: List[T]) -> None: pass
[builtins fixtures/list.pyi]
Expand Down Expand Up @@ -1752,14 +1753,11 @@ reveal_type(f(d)) # N: Revealed type is "builtins.list[builtins.int]"
from typing import overload, Any

@overload
def f(*, x: int = 3, y: int = 3) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def f(*, x: int = 3, y: int = 3) -> int: ...
@overload
def f(**kwargs: str) -> str: ...
def f(*args, **kwargs): pass

# Checking an overload flagged as unsafe is a bit weird, but this is the
# cleanest way to make sure 'Any' ambiguity checks work correctly with
# keyword arguments.
a: Any
i: int
reveal_type(f(x=a, y=i)) # N: Revealed type is "builtins.int"
Expand Down Expand Up @@ -2163,8 +2161,9 @@ from wrapper import *
[file wrapper.pyi]
from typing import overload

# Safety of this highly depends on the implementation, so we lean towards being silent.
@overload
def foo1(*x: int) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo1(*x: int) -> int: ...
@overload
def foo1(x: int, y: int, z: int) -> str: ...

Expand All @@ -2173,8 +2172,9 @@ def foo2(*x: int) -> int: ...
@overload
def foo2(x: int, y: str, z: int) -> str: ...

# Note: this is technically unsafe, but we don't report this for now.
@overload
def bar1(x: int, y: int, z: int) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def bar1(x: int, y: int, z: int) -> str: ...
@overload
def bar1(*x: int) -> int: ...

Expand Down Expand Up @@ -2248,7 +2248,7 @@ from wrapper import *
from typing import overload

@overload
def foo1(x: str) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo1(x: str) -> str: ...
@overload
def foo1(x: str, y: str = ...) -> int: ...

Expand All @@ -2268,12 +2268,12 @@ from wrapper import *
from typing import overload

@overload
def foo1(*args: int) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo1(*args: int) -> int: ...
@overload
def foo1(**kwargs: int) -> str: ...

@overload
def foo2(**kwargs: int) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo2(**kwargs: int) -> str: ...
@overload
def foo2(*args: int) -> int: ...
[builtins fixtures/dict.pyi]
Expand Down Expand Up @@ -2314,13 +2314,14 @@ def foo2(x: int, *args: int) -> str: ...
@overload
def foo2(*args2: str) -> int: ...

# The two examples are unsafe, but this is hard to detect.
@overload
def foo3(*args: int) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo3(*args: int) -> int: ...
@overload
def foo3(x: int, *args2: int) -> str: ...

@overload
def foo4(x: int, *args: int) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo4(x: int, *args: int) -> str: ...
@overload
def foo4(*args2: int) -> int: ...
[builtins fixtures/tuple.pyi]
Expand Down Expand Up @@ -2357,13 +2358,13 @@ def foo4(x: Other = ..., *args: str) -> int: ...
from typing import overload

@overload
def foo1(x: int = 0, y: int = 0) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo1(x: int = 0, y: int = 0) -> int: ...
@overload
def foo1(*xs: int) -> str: ...
def foo1(*args): pass

@overload
def foo2(*xs: int) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo2(*xs: int) -> str: ...
@overload
def foo2(x: int = 0, y: int = 0) -> int: ...
def foo2(*args): pass
Expand Down Expand Up @@ -2412,12 +2413,12 @@ from wrapper import *
from typing import overload

@overload
def foo1(x: str, y: str = ..., z: str = ...) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo1(x: str, y: str = ..., z: str = ...) -> str: ...
@overload
def foo1(*x: str) -> int: ...

@overload
def foo2(*x: str) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo2(*x: str) -> int: ...
@overload
def foo2(x: str, y: str = ..., z: str = ...) -> str: ...

Expand All @@ -2433,12 +2434,12 @@ from wrapper import *
from typing import overload

@overload
def foo1(x: str, y: str = ..., z: int = ...) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo1(x: str, y: str = ..., z: int = ...) -> str: ...
@overload
def foo1(*x: str) -> int: ...

@overload
def foo2(x: str, y: str = ..., z: int = ...) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo2(x: str, y: str = ..., z: int = ...) -> str: ...
@overload
def foo2(*x: str) -> int: ...
[builtins fixtures/tuple.pyi]
Expand All @@ -2449,7 +2450,7 @@ from wrapper import *
from typing import overload

@overload
def foo1(*, x: str, y: str, z: str) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo1(*, x: str, y: str, z: str) -> str: ...
@overload
def foo1(**x: str) -> int: ...

Expand Down Expand Up @@ -2481,12 +2482,12 @@ def foo2(**x: str) -> int: ...
def foo2(*, x: str, y: str, z: int) -> str: ...

@overload
def foo3(*, x: str, y: str, z: int = ...) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo3(*, x: str, y: str, z: int = ...) -> str: ...
@overload
def foo3(**x: str) -> int: ...

@overload
def foo4(**x: str) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo4(**x: str) -> int: ...
@overload
def foo4(*, x: str, y: str, z: int = ...) -> str: ...
[builtins fixtures/dict.pyi]
Expand All @@ -2502,7 +2503,7 @@ def foo1(x: str, *, y: str, z: str) -> str: ... # E: Overloaded function signat
def foo1(**x: str) -> int: ...

@overload
def foo2(**x: str) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def foo2(**x: str) -> int: ...
@overload
def foo2(x: str, *, y: str, z: str) -> str: ...

Expand Down Expand Up @@ -2810,8 +2811,9 @@ from typing import TypeVar, overload

T = TypeVar('T')

# Note: this is unsafe, but it is hard to detect.
@overload
def f(x: int) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def f(x: int) -> str: ...
@overload
def f(x: T) -> T: ...
def f(x): ...
Expand All @@ -2827,14 +2829,15 @@ from typing import TypeVar, overload, List

T = TypeVar('T')

# Note: first two examples are unsafe, but it is hard to detect.
@overload
def f1(x: List[int]) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def f1(x: List[int]) -> str: ...
@overload
def f1(x: List[T]) -> T: ...
def f1(x): ...

@overload
def f2(x: List[int]) -> List[str]: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def f2(x: List[int]) -> List[str]: ...
@overload
def f2(x: List[T]) -> List[T]: ...
def f2(x): ...
Expand All @@ -2859,8 +2862,9 @@ from typing import TypeVar, overload, Generic
T = TypeVar('T')

class Wrapper(Generic[T]):
# Similar to above: this is unsafe, but it is hard to detect.
@overload
def f(self, x: int) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def f(self, x: int) -> str: ...
@overload
def f(self, x: T) -> T: ...
def f(self, x): ...
Expand All @@ -2877,14 +2881,15 @@ from typing import TypeVar, overload, Generic, List
T = TypeVar('T')

class Wrapper(Generic[T]):
# Similar to above: first two examples are unsafe, but it is hard to detect.
@overload
def f1(self, x: List[int]) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def f1(self, x: List[int]) -> str: ...
@overload
def f1(self, x: List[T]) -> T: ...
def f1(self, x): ...

@overload
def f2(self, x: List[int]) -> List[str]: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def f2(self, x: List[int]) -> List[str]: ...
@overload
def f2(self, x: List[T]) -> List[T]: ...
def f2(self, x): ...
Expand Down Expand Up @@ -3079,7 +3084,7 @@ def f(x: Union[B, C]) -> str: ...
def f(x): pass

@overload
def g(x: Union[B, C]) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def g(x: Union[B, C]) -> int: ...
@overload
def g(x: S) -> str: ...
def g(x): pass
Expand Down Expand Up @@ -4898,7 +4903,7 @@ T = TypeVar('T')

def f() -> None:
@overload
def g(x: str) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def g(x: str) -> int: ...
@overload
def g(x: T) -> T: ...
def g(x):
Expand Down Expand Up @@ -5314,7 +5319,7 @@ def f1(g: G[A, B]) -> B: ...
def f1(g: Any) -> Any: ...

@overload
def f2(g: G[A, Any]) -> A: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def f2(g: G[A, Any]) -> A: ...
@overload
def f2(g: G[A, B], x: int = ...) -> B: ...
def f2(g: Any, x: int = ...) -> Any: ...
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-parameter-specification.test
Original file line number Diff line number Diff line change
Expand Up @@ -1600,7 +1600,7 @@ from typing_extensions import Concatenate, ParamSpec
P = ParamSpec("P")

@overload
def command() -> Callable[[Callable[Concatenate[object, object, P], object]], None]: # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
def command() -> Callable[[Callable[Concatenate[object, object, P], object]], None]:
...

@overload
Expand Down
Loading