| -- Test cases for function overloading | |
| [case testOverloadNotImportedNoCrash] | |
| @overload | |
| def f(a): pass | |
| @overload | |
| def f(a): pass | |
| def f(a): pass | |
| f(0) | |
| @overload # E: Name "overload" is not defined | |
| def g(a:int): pass | |
| def g(a): pass # E: Name "g" already defined on line 9 | |
| g(0) | |
| @something # E: Name "something" is not defined | |
| def r(a:int): pass | |
| def r(a): pass # E: Name "r" already defined on line 14 | |
| r(0) | |
| [out] | |
| main:2: error: Name "overload" is not defined | |
| main:4: error: Name "f" already defined on line 2 | |
| main:4: error: Name "overload" is not defined | |
| main:6: error: Name "f" already defined on line 2 | |
| [case testTypeCheckOverloadWithImplementation] | |
| from typing import overload, Any | |
| class A: pass | |
| class B: pass | |
| @overload | |
| def f(x: 'A') -> 'B': ... | |
| @overload | |
| def f(x: 'B') -> 'A': ... | |
| def f(x: Any) -> Any: | |
| pass | |
| reveal_type(f(A())) # N: Revealed type is "__main__.B" | |
| reveal_type(f(B())) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testTypingExtensionsOverload] | |
| from typing import Any | |
| from typing_extensions import overload | |
| class A: pass | |
| class B: pass | |
| @overload | |
| def f(x: 'A') -> 'B': ... | |
| @overload | |
| def f(x: 'B') -> 'A': ... | |
| def f(x: Any) -> Any: | |
| pass | |
| reveal_type(f(A())) # N: Revealed type is "__main__.B" | |
| reveal_type(f(B())) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testOverloadNeedsImplementation] | |
| from typing import overload, Any | |
| class A: pass | |
| class B: pass | |
| @overload # E: An overloaded function outside a stub file must have an implementation | |
| def f(x: 'A') -> 'B': ... | |
| @overload | |
| def f(x: 'B') -> 'A': ... | |
| reveal_type(f(A())) # N: Revealed type is "__main__.B" | |
| reveal_type(f(B())) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testSingleOverloadNoImplementation] | |
| from typing import overload, Any | |
| @overload # E: Single overload definition, multiple required | |
| def f(x: 'A') -> 'B': ... | |
| class A: pass | |
| class B: pass | |
| [builtins fixtures/isinstance.pyi] | |
| [case testOverloadByAnyOtherName] | |
| from typing import overload as rose | |
| from typing import Any | |
| class A: pass | |
| class B: pass | |
| @rose | |
| def f(x: 'A') -> 'B': ... | |
| @rose | |
| def f(x: 'B') -> 'A': ... | |
| def f(x: Any) -> Any: | |
| pass | |
| reveal_type(f(A())) # N: Revealed type is "__main__.B" | |
| reveal_type(f(B())) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testTypeCheckOverloadWithDecoratedImplementation] | |
| from typing import overload, Any | |
| class A: pass | |
| class B: pass | |
| def deco(fun): ... | |
| @overload | |
| def f(x: 'A') -> 'B': ... | |
| @overload | |
| def f(x: 'B') -> 'A': ... | |
| @deco | |
| def f(x: Any) -> Any: | |
| pass | |
| reveal_type(f(A())) # N: Revealed type is "__main__.B" | |
| reveal_type(f(B())) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testOverloadDecoratedImplementationNotLast] | |
| from typing import overload, Any | |
| def deco(fun): ... | |
| @overload | |
| def f(x: 'A') -> 'B': ... | |
| @deco # E: The implementation for an overloaded function must come last | |
| def f(x: Any) -> Any: | |
| pass | |
| @overload | |
| def f(x: 'B') -> 'A': ... | |
| class A: pass | |
| class B: pass | |
| [builtins fixtures/isinstance.pyi] | |
| [case testOverloadImplementationNotLast] | |
| from typing import overload, Any | |
| @overload | |
| def f(x: 'A') -> 'B': ... | |
| def f(x: Any) -> Any: # E: The implementation for an overloaded function must come last | |
| pass | |
| @overload | |
| def f(x: 'B') -> 'A': ... | |
| class A: pass | |
| class B: pass | |
| [builtins fixtures/isinstance.pyi] | |
| [case testDecoratedRedefinitionIsNotOverload] | |
| from typing import overload, Any | |
| def deco(fun): ... | |
| @deco | |
| def f(x: 'A') -> 'B': ... | |
| @deco # E: Name "f" already defined on line 5 | |
| def f(x: 'B') -> 'A': ... | |
| @deco # E: Name "f" already defined on line 5 | |
| def f(x: Any) -> Any: ... | |
| class A: pass | |
| class B: pass | |
| [builtins fixtures/isinstance.pyi] | |
| [case testTypeCheckOverloadWithImplementationError] | |
| from typing import overload, Any | |
| class A: pass | |
| class B: pass | |
| @overload | |
| def f(x: 'A') -> 'B': ... | |
| @overload | |
| def f(x: 'B') -> 'A': ... | |
| def f(x: Any) -> Any: | |
| foo = 1 | |
| if int(): | |
| foo = "bar" # E: Incompatible types in assignment (expression has type "str", variable has type "int") | |
| @overload | |
| def g(x: 'A') -> 'B': ... | |
| @overload | |
| def g(x: 'B') -> 'A': ... | |
| def g(x): | |
| foo = 1 | |
| if int(): | |
| foo = "bar" | |
| reveal_type(f(A())) # N: Revealed type is "__main__.B" | |
| reveal_type(f(B())) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testTypeCheckOverloadWithUntypedImplAndMultipleVariants] | |
| from typing import overload | |
| @overload | |
| def f(x: int) -> str: ... | |
| @overload | |
| def f(x: str) -> int: ... # E: Overloaded function signatures 2 and 3 overlap with incompatible return types | |
| @overload | |
| def f(x: object) -> str: ... | |
| def f(x): ... | |
| [case testTypeCheckOverloadWithImplTooSpecificArg] | |
| from typing import overload, Any | |
| class A: pass | |
| class B: pass | |
| a = A() | |
| @overload | |
| def f(x: 'A') -> 'B': ... | |
| @overload | |
| def f(x: 'B') -> 'A': ... | |
| def f(x: 'A') -> Any: # E: Overloaded function implementation does not accept all possible parameters of signature 2 | |
| pass | |
| reveal_type(f(A())) # N: Revealed type is "__main__.B" | |
| reveal_type(f(B())) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testTypeCheckOverloadImplOverlapVarArgsAndKwargs] | |
| from __future__ import annotations | |
| from typing import overload | |
| @overload | |
| def foo(x: int) -> None: ... | |
| @overload | |
| def foo(a: str, /) -> None: ... | |
| def foo(*args: int | str, **kw: int) -> None: | |
| pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testTypeCheckOverloadImplOverlapVarArgsAndKwargsUnion] | |
| from __future__ import annotations | |
| from typing import overload | |
| class Foo: ... | |
| @overload | |
| def foo(x: int) -> None: ... | |
| @overload | |
| def foo(*, x: Foo) -> None: ... | |
| @overload | |
| def foo(a: str, /) -> None: ... | |
| def foo(*args: int | str, **kw: int | Foo) -> None: | |
| pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testTypeCheckOverloadImplOverlapVarArgsAndKwargsNever] | |
| from __future__ import annotations | |
| from typing import overload | |
| @overload # E: Single overload definition, multiple required | |
| def foo(x: int) -> None: ... | |
| def foo(*args: int, **kw: str) -> None: # E: Overloaded function implementation does not accept all possible parameters of signature 1 | |
| pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testTypeCheckOverloadWithImplTooSpecificRetType] | |
| from typing import overload, Any | |
| class A: pass | |
| class B: pass | |
| a = A() | |
| @overload | |
| def f(x: 'A') -> 'B': ... | |
| @overload | |
| def f(x: 'B') -> 'A': ... | |
| def f(x: Any) -> 'B': # E: Overloaded function implementation cannot produce return type of signature 2 | |
| return B() | |
| reveal_type(f(A())) # N: Revealed type is "__main__.B" | |
| reveal_type(f(B())) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testTypeCheckOverloadWithImplTypeVar] | |
| from typing import overload, Any, TypeVar | |
| T = TypeVar('T') | |
| class A: pass | |
| class B: pass | |
| a = A() | |
| @overload | |
| def f(x: 'A') -> 'A': ... | |
| @overload | |
| def f(x: 'B') -> 'B': ... | |
| def f(x: T) -> T: | |
| ... | |
| reveal_type(f(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f(B())) # N: Revealed type is "__main__.B" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testTypeCheckOverloadWithImplTypeVarProblems] | |
| from typing import overload, Any, TypeVar, Union | |
| T = TypeVar('T', bound='A') | |
| class A: pass | |
| class B: pass | |
| a = A() | |
| @overload | |
| def f(x: 'A') -> 'A': ... | |
| @overload | |
| def f(x: 'B') -> 'B': ... | |
| def f(x: Union[T, B]) -> T: # E: Overloaded function implementation cannot satisfy signature 2 due to inconsistencies in how they use type variables | |
| ... | |
| reveal_type(f(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f(B())) # N: Revealed type is "__main__.B" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testTypeCheckOverloadImplementationTypeVarWithValueRestriction] | |
| from typing import overload, TypeVar, Union | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| T = TypeVar('T', A, B) | |
| @overload | |
| def foo(x: T) -> T: ... | |
| @overload | |
| def foo(x: C) -> int: ... | |
| def foo(x: Union[A, B, C]) -> Union[A, B, int]: | |
| if isinstance(x, C): | |
| return 3 | |
| else: | |
| return x | |
| @overload | |
| def bar(x: T) -> T: ... | |
| @overload | |
| def bar(x: C) -> int: ... | |
| def bar(x: Union[T, C]) -> Union[T, int]: | |
| if isinstance(x, C): | |
| return 3 | |
| else: | |
| return x | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testTypeCheckOverloadImplementationTypeVarDifferingUsage1] | |
| from typing import overload, Union, List, TypeVar, Generic | |
| T = TypeVar('T') | |
| @overload | |
| def foo(t: List[T]) -> T: ... | |
| @overload | |
| def foo(t: T) -> T: ... | |
| def foo(t: Union[List[T], T]) -> T: | |
| if isinstance(t, list): | |
| return t[0] | |
| else: | |
| return t | |
| class Wrapper(Generic[T]): | |
| @overload | |
| def foo(self, t: List[T]) -> T: ... | |
| @overload | |
| def foo(self, t: T) -> T: ... | |
| def foo(self, t: Union[List[T], T]) -> T: | |
| if isinstance(t, list): | |
| return t[0] | |
| else: | |
| return t | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testTypeCheckOverloadImplementationTypeVarDifferingUsage2] | |
| from typing import overload, Union, List, TypeVar, Generic | |
| T = TypeVar('T') | |
| # Note: this is unsafe when T = object | |
| @overload | |
| def foo(t: List[T], s: T) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def foo(t: T, s: T) -> str: ... | |
| def foo(t, s): pass | |
| class Wrapper(Generic[T]): | |
| @overload | |
| def foo(self, t: List[T], s: T) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types \ | |
| # N: Flipping the order of overloads will fix this error | |
| @overload | |
| def foo(self, t: T, s: T) -> str: ... | |
| def foo(self, t, s): pass | |
| class Dummy(Generic[T]): pass | |
| # Same root issue: why does the additional constraint bound T <: T | |
| # cause the constraint solver to not infer T = object like it did in the | |
| # first example? | |
| @overload | |
| def bar(d: Dummy[T], t: List[T], s: T) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types \ | |
| # N: Flipping the order of overloads will fix this error | |
| @overload | |
| def bar(d: Dummy[T], t: T, s: T) -> str: ... | |
| def bar(d: Dummy[T], t, s): pass | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testTypeCheckOverloadedFunctionBody] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| @overload | |
| def f(x: 'A'): | |
| if int(): | |
| x = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A") | |
| x = A() | |
| @overload | |
| def f(x: 'B'): | |
| if int(): | |
| x = A() # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| x = B() | |
| class A: pass | |
| class B: pass | |
| [out] | |
| [case testTypeCheckOverloadedMethodBody] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class A: | |
| @overload | |
| def f(self, x: 'A'): | |
| if int(): | |
| x = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A") | |
| x = A() | |
| @overload | |
| def f(self, x: 'B'): | |
| if int(): | |
| x = A() # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| x = B() | |
| class B: pass | |
| [out] | |
| [case testCallToOverloadedFunction] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| f(C()) # E: No overload variant of "f" matches argument type "C" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(x: A) -> None \ | |
| # N: def f(x: B) -> None | |
| f(A()) | |
| f(B()) | |
| @overload | |
| def f(x: 'A') -> None: pass | |
| @overload | |
| def f(x: 'B') -> None: pass | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| [case testOverloadedFunctionReturnValue] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| a: A | |
| b: B | |
| if int(): | |
| b = f(a) # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| a = f(b) # E: Incompatible types in assignment (expression has type "B", variable has type "A") | |
| if int(): | |
| a = f(a) | |
| if int(): | |
| b = f(b) | |
| @overload | |
| def f(x: 'A') -> 'A': pass | |
| @overload | |
| def f(x: 'B') -> 'B': pass | |
| class A: pass | |
| class B: pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testCallToOverloadedMethod] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| A().f(C()) # E: No overload variant of "f" of "A" matches argument type "C" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(self, x: A) -> None \ | |
| # N: def f(self, x: B) -> None | |
| A().f(A()) | |
| A().f(B()) | |
| class A: | |
| @overload | |
| def f(self, x: 'A') -> None: pass | |
| @overload | |
| def f(self, x: 'B') -> None: pass | |
| class B: pass | |
| class C: pass | |
| [case testOverloadedMethodReturnValue] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| a: A | |
| b: B | |
| if int(): | |
| b = a.f(a) # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| a = a.f(b) # E: Incompatible types in assignment (expression has type "B", variable has type "A") | |
| if int(): | |
| a = a.f(a) | |
| if int(): | |
| b = a.f(b) | |
| class A: | |
| @overload | |
| def f(self, x: 'A') -> 'A': pass | |
| @overload | |
| def f(self, x: 'B') -> 'B': pass | |
| class B: pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadsWithDifferentArgumentCounts] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| a: A | |
| b: B | |
| if int(): | |
| a = f(a) | |
| if int(): | |
| b = f(a) # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| f(b) # E: No overload variant of "f" matches argument type "B" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(x: A) -> A \ | |
| # N: def f(x: B, y: A) -> B | |
| if int(): | |
| b = f(b, a) | |
| if int(): | |
| a = f(b, a) # E: Incompatible types in assignment (expression has type "B", variable has type "A") | |
| f(a, a) # E: No overload variant of "f" matches argument types "A", "A" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(x: A) -> A \ | |
| # N: def f(x: B, y: A) -> B | |
| f(b, b) # E: No overload variant of "f" matches argument types "B", "B" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(x: A) -> A \ | |
| # N: def f(x: B, y: A) -> B | |
| @overload | |
| def f(x: 'A') -> 'A': pass | |
| @overload | |
| def f(x: 'B', y: 'A') -> 'B': pass | |
| class A: pass | |
| class B: pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testGenericOverloadVariant] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, TypeVar, Generic | |
| t = TypeVar('t') | |
| ab: A[B] | |
| ac: A[C] | |
| b: B | |
| c: C | |
| if int(): | |
| b = f(ab) | |
| c = f(ac) | |
| b = f(ac) # E: Incompatible types in assignment (expression has type "C", variable has type "B") | |
| b = f(b) | |
| c = f(b) # E: Incompatible types in assignment (expression has type "B", variable has type "C") | |
| @overload | |
| def f(x: 'A[t]') -> t: pass | |
| @overload | |
| def f(x: 'B') -> 'B': pass | |
| class A(Generic[t]): pass | |
| class B: pass | |
| class C: pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadedInit] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| a: A | |
| b: B | |
| a = A(a) | |
| a = A(b) | |
| a = A(object()) # E: No overload variant of "A" matches argument type "object" \ | |
| # N: Possible overload variants: \ | |
| # N: def A(a: A) -> A \ | |
| # N: def A(b: B) -> A | |
| class A: | |
| @overload | |
| def __init__(self, a: 'A') -> None: pass | |
| @overload | |
| def __init__(self, b: 'B') -> None: pass | |
| class B: pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testIntersectionTypeCompatibility] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, Callable | |
| o: object | |
| a: A | |
| if int(): | |
| a = f # E: Incompatible types in assignment (expression has type overloaded function, variable has type "A") | |
| if int(): | |
| o = f | |
| @overload | |
| def f(a: 'A') -> None: pass | |
| @overload | |
| def f(a: Callable[[], None]) -> None: pass | |
| class A: pass | |
| [case testCompatibilityOfIntersectionTypeObjectWithStdType] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| t: type | |
| a: A | |
| if int(): | |
| a = A # E: Incompatible types in assignment (expression has type "type[A]", variable has type "A") | |
| t = A | |
| class A: | |
| @overload | |
| def __init__(self, a: 'A') -> None: pass | |
| @overload | |
| def __init__(self, a: 'B') -> None: pass | |
| class B: pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadedGetitem] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| a: int | |
| b: str | |
| if int(): | |
| a = A()[a] | |
| if int(): | |
| b = A()[a] # E: Incompatible types in assignment (expression has type "int", variable has type "str") | |
| if int(): | |
| b = A()[b] | |
| if int(): | |
| a = A()[b] # E: Incompatible types in assignment (expression has type "str", variable has type "int") | |
| class A: | |
| @overload | |
| def __getitem__(self, a: int) -> int: pass | |
| @overload | |
| def __getitem__(self, b: str) -> str: pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadedGetitemWithGenerics] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import TypeVar, Generic, overload | |
| t = TypeVar('t') | |
| a: A | |
| b: B | |
| c: C[A] | |
| if int(): | |
| a = c[a] | |
| b = c[a] # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| a = c[b] | |
| b = c[b] # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| class C(Generic[t]): | |
| @overload | |
| def __getitem__(self, a: 'A') -> t: pass | |
| @overload | |
| def __getitem__(self, b: 'B') -> t: pass | |
| class A: pass | |
| class B: pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testImplementingOverloadedMethod] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| from abc import abstractmethod, ABCMeta | |
| class I(metaclass=ABCMeta): | |
| @overload | |
| @abstractmethod | |
| def f(self) -> None: pass | |
| @overload | |
| @abstractmethod | |
| def f(self, a: 'A') -> None: pass | |
| class A(I): | |
| @overload | |
| def f(self) -> None: pass | |
| @overload | |
| def f(self, a: 'A') -> None: pass | |
| [case testOverloadWithFunctionType] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, Callable | |
| class A: pass | |
| @overload | |
| def f(x: A) -> None: pass | |
| @overload | |
| def f(x: Callable[[], None]) -> None: pass | |
| f(A()) | |
| [builtins fixtures/function.pyi] | |
| [case testVarArgsOverload] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, Any | |
| @overload | |
| def f(x: 'A', *more: Any) -> 'A': pass | |
| @overload | |
| def f(x: 'B', *more: Any) -> 'A': pass | |
| f(A()) | |
| f(A(), A, A) | |
| f(B()) | |
| f(B(), B) | |
| f(B(), B, B) | |
| f(object()) # E: No overload variant of "f" matches argument type "object" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(x: A, *more: Any) -> A \ | |
| # N: def f(x: B, *more: Any) -> A | |
| class A: pass | |
| class B: pass | |
| [builtins fixtures/list.pyi] | |
| [case testVarArgsOverload2] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| @overload | |
| def f(x: 'A', *more: 'B') -> 'A': pass | |
| @overload | |
| def f(x: 'B', *more: 'A') -> 'A': pass | |
| f(A(), B()) | |
| f(A(), B(), B()) | |
| f(A(), A(), B()) # E: No overload variant of "f" matches argument types "A", "A", "B" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(x: A, *more: B) -> A \ | |
| # N: def f(x: B, *more: A) -> A | |
| f(A(), B(), A()) # E: No overload variant of "f" matches argument types "A", "B", "A" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(x: A, *more: B) -> A \ | |
| # N: def f(x: B, *more: A) -> A | |
| class A: pass | |
| class B: pass | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadWithTypeObject] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| @overload | |
| def f(a: 'A', t: type) -> None: pass | |
| @overload | |
| def f(a: 'B', t: type) -> None: pass | |
| f(A(), B) | |
| f(B(), A) | |
| class A: pass | |
| class B: pass | |
| [builtins fixtures/function.pyi] | |
| [case testOverloadedInitAndTypeObjectInOverload] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| @overload | |
| def f(t: type) -> 'A': pass | |
| @overload | |
| def f(t: 'A') -> 'B': pass | |
| a: A | |
| b: B | |
| if int(): | |
| a = f(A) | |
| if int(): | |
| b = f(a) | |
| if int(): | |
| b = f(A) # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| a = f(a) # E: Incompatible types in assignment (expression has type "B", variable has type "A") | |
| class A: | |
| @overload | |
| def __init__(self) -> None: pass | |
| @overload | |
| def __init__(self, a: 'A') -> None: pass | |
| class B: | |
| pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverlappingErasedSignatures] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, List | |
| @overload | |
| def f(a: List[int]) -> int: pass | |
| @overload | |
| def f(a: List[str]) -> int: pass | |
| list_int = [] # type: List[int] | |
| list_str = [] # type: List[str] | |
| list_object = [] # type: List[object] | |
| n = f(list_int) | |
| m = f(list_str) | |
| def p(): n, m # Prevent redefinition | |
| n = 1 | |
| m = 1 | |
| n = 'x' # E: Incompatible types in assignment (expression has type "str", variable has type "int") | |
| m = 'x' # E: Incompatible types in assignment (expression has type "str", variable has type "int") | |
| f(list_object) # E: Argument 1 to "f" has incompatible type "list[object]"; expected "list[int]" | |
| [builtins fixtures/list.pyi] | |
| [case testOverlappingOverloadSignatures] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class A: pass | |
| class B(A): pass | |
| @overload | |
| def f(x: B) -> int: pass # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: A) -> str: pass | |
| [case testContravariantOverlappingOverloadSignatures] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class A: pass | |
| class B(A): pass | |
| @overload | |
| def f(x: A) -> A: pass | |
| @overload | |
| def f(x: B) -> B: pass # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader | |
| [case testPartiallyCovariantOverlappingOverloadSignatures] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class A: pass | |
| class B(A): pass | |
| @overload | |
| def f(x: B) -> A: pass # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: A) -> B: pass | |
| [case testPartiallyContravariantOverloadSignatures] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class A: pass | |
| class B(A): pass | |
| @overload | |
| def g(x: A) -> int: pass | |
| @overload | |
| def g(x: B) -> str: pass # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader | |
| [case testCovariantOverlappingOverloadSignatures] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class A: pass | |
| class B(A): pass | |
| @overload | |
| def g(x: B) -> B: pass | |
| @overload | |
| def g(x: A) -> A: pass | |
| [case testCovariantOverlappingOverloadSignaturesWithSomeSameArgTypes] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class A: pass | |
| class B(A): pass | |
| @overload | |
| def g(x: int, y: B) -> B: pass | |
| @overload | |
| def g(x: int, y: A) -> A: pass | |
| [case testCovariantOverlappingOverloadSignaturesWithAnyType] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import Any, overload | |
| @overload | |
| def g(x: int) -> int: pass | |
| @overload | |
| def g(x: Any) -> Any: pass | |
| [case testContravariantOverlappingOverloadSignaturesWithAnyType] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import Any, overload | |
| @overload | |
| def g(x: Any) -> Any: pass | |
| @overload | |
| def g(x: int) -> int: pass # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader | |
| [case testOverloadedLtAndGtMethods] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class A: | |
| def __lt__(self, x: A) -> int: pass | |
| def __gt__(self, x: A) -> int: pass | |
| class B: | |
| @overload | |
| def __lt__(self, x: B) -> int: pass | |
| @overload | |
| def __lt__(self, x: A) -> int: pass | |
| @overload | |
| def __gt__(self, x: B) -> int: pass | |
| @overload | |
| def __gt__(self, x: A) -> int: pass | |
| A() < A() | |
| A() < B() | |
| B() < A() | |
| B() < B() | |
| A() < object() # E: Unsupported operand types for < ("A" and "object") | |
| B() < object() # E: No overload variant of "__lt__" of "B" matches argument type "object" \ | |
| # N: Possible overload variants: \ | |
| # N: def __lt__(self, B, /) -> int \ | |
| # N: def __lt__(self, A, /) -> int | |
| [case testOverloadedForwardMethodAndCallingReverseMethod] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class A: | |
| @overload | |
| def __add__(self, x: 'A') -> int: pass | |
| @overload | |
| def __add__(self, x: int) -> int: pass | |
| class B: | |
| def __radd__(self, x: A) -> int: pass | |
| A() + A() | |
| A() + 1 | |
| A() + B() | |
| A() + '' # E: No overload variant of "__add__" of "A" matches argument type "str" \ | |
| # N: Possible overload variants: \ | |
| # N: def __add__(self, A, /) -> int \ | |
| # N: def __add__(self, int, /) -> int | |
| [case testOverrideOverloadSwapped] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class Parent: | |
| @overload | |
| def f(self, x: int) -> int: ... | |
| @overload | |
| def f(self, x: str) -> str: ... | |
| class Child(Parent): | |
| @overload # E: Signature of "f" incompatible with supertype "Parent" \ | |
| # N: Overload variants must be defined in the same order as they are in "Parent" | |
| def f(self, x: str) -> str: ... | |
| @overload | |
| def f(self, x: int) -> int: ... | |
| [case testOverrideOverloadSwappedWithExtraVariants] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class bool: pass | |
| class Parent: | |
| @overload | |
| def f(self, x: int) -> int: ... | |
| @overload | |
| def f(self, x: str) -> str: ... | |
| class Child1(Parent): | |
| @overload # E: Signature of "f" incompatible with supertype "Parent" \ | |
| # N: Overload variants must be defined in the same order as they are in "Parent" | |
| def f(self, x: bool) -> bool: ... | |
| @overload | |
| def f(self, x: str) -> str: ... | |
| @overload | |
| def f(self, x: int) -> int: ... | |
| class Child2(Parent): | |
| @overload # E: Signature of "f" incompatible with supertype "Parent" \ | |
| # N: Overload variants must be defined in the same order as they are in "Parent" | |
| def f(self, x: str) -> str: ... | |
| @overload | |
| def f(self, x: bool) -> bool: ... | |
| @overload | |
| def f(self, x: int) -> int: ... | |
| class Child3(Parent): | |
| @overload # E: Signature of "f" incompatible with supertype "Parent" \ | |
| # N: Overload variants must be defined in the same order as they are in "Parent" | |
| def f(self, x: str) -> str: ... | |
| @overload | |
| def f(self, x: int) -> int: ... | |
| @overload | |
| def f(self, x: bool) -> bool: ... | |
| [case testOverrideOverloadSwappedWithAdjustedVariants] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class A: pass | |
| class B(A): pass | |
| class C(B): pass | |
| class Parent: | |
| @overload | |
| def f(self, x: int) -> int: ... | |
| @overload | |
| def f(self, x: B) -> B: ... | |
| class Child1(Parent): | |
| @overload # Fail | |
| def f(self, x: A) -> B: ... | |
| @overload | |
| def f(self, x: int) -> int: ... | |
| class Child2(Parent): | |
| @overload # Fail | |
| def f(self, x: B) -> C: ... | |
| @overload | |
| def f(self, x: int) -> int: ... | |
| class Child3(Parent): | |
| @overload # Fail | |
| def f(self, x: B) -> A: ... | |
| @overload | |
| def f(self, x: int) -> int: ... | |
| [out] | |
| tmp/foo.pyi:13: error: Signature of "f" incompatible with supertype "Parent" | |
| tmp/foo.pyi:13: note: Overload variants must be defined in the same order as they are in "Parent" | |
| tmp/foo.pyi:18: error: Signature of "f" incompatible with supertype "Parent" | |
| tmp/foo.pyi:18: note: Overload variants must be defined in the same order as they are in "Parent" | |
| tmp/foo.pyi:23: error: Signature of "f" incompatible with supertype "Parent" | |
| tmp/foo.pyi:23: note: Superclass: | |
| tmp/foo.pyi:23: note: @overload | |
| tmp/foo.pyi:23: note: def f(self, x: int) -> int | |
| tmp/foo.pyi:23: note: @overload | |
| tmp/foo.pyi:23: note: def f(self, x: B) -> B | |
| tmp/foo.pyi:23: note: Subclass: | |
| tmp/foo.pyi:23: note: @overload | |
| tmp/foo.pyi:23: note: def f(self, x: B) -> A | |
| tmp/foo.pyi:23: note: @overload | |
| tmp/foo.pyi:23: note: def f(self, x: int) -> int | |
| [case testOverrideOverloadedMethodWithMoreGeneralArgumentTypes] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class IntSub(int): pass | |
| class StrSub(str): pass | |
| class A: | |
| @overload | |
| def f(self, x: IntSub) -> int: return 0 | |
| @overload | |
| def f(self, x: StrSub) -> str: return '' | |
| class B(A): | |
| @overload | |
| def f(self, x: int) -> int: return 0 | |
| @overload | |
| def f(self, x: str) -> str: return '' | |
| [out] | |
| [case testOverrideOverloadedMethodWithMoreSpecificArgumentTypes] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class IntSub(int): pass | |
| class StrSub(str): pass | |
| class A: | |
| @overload | |
| def f(self, x: int) -> int: return 0 | |
| @overload | |
| def f(self, x: str) -> str: return '' | |
| class B(A): | |
| @overload # Fail | |
| def f(self, x: IntSub) -> int: return 0 | |
| @overload | |
| def f(self, x: str) -> str: return '' | |
| class C(A): | |
| @overload # Fail | |
| def f(self, x: int) -> int: return 0 | |
| @overload | |
| def f(self, x: StrSub) -> str: return '' | |
| class D(A): | |
| @overload | |
| def f(self, x: int) -> int: return 0 | |
| @overload | |
| def f(self, x: str) -> str: return '' | |
| [out] | |
| tmp/foo.pyi:12: error: Signature of "f" incompatible with supertype "A" | |
| tmp/foo.pyi:12: note: Superclass: | |
| tmp/foo.pyi:12: note: @overload | |
| tmp/foo.pyi:12: note: def f(self, x: int) -> int | |
| tmp/foo.pyi:12: note: @overload | |
| tmp/foo.pyi:12: note: def f(self, x: str) -> str | |
| tmp/foo.pyi:12: note: Subclass: | |
| tmp/foo.pyi:12: note: @overload | |
| tmp/foo.pyi:12: note: def f(self, x: IntSub) -> int | |
| tmp/foo.pyi:12: note: @overload | |
| tmp/foo.pyi:12: note: def f(self, x: str) -> str | |
| tmp/foo.pyi:17: error: Signature of "f" incompatible with supertype "A" | |
| tmp/foo.pyi:17: note: Superclass: | |
| tmp/foo.pyi:17: note: @overload | |
| tmp/foo.pyi:17: note: def f(self, x: int) -> int | |
| tmp/foo.pyi:17: note: @overload | |
| tmp/foo.pyi:17: note: def f(self, x: str) -> str | |
| tmp/foo.pyi:17: note: Subclass: | |
| tmp/foo.pyi:17: note: @overload | |
| tmp/foo.pyi:17: note: def f(self, x: int) -> int | |
| tmp/foo.pyi:17: note: @overload | |
| tmp/foo.pyi:17: note: def f(self, x: StrSub) -> str | |
| [case testOverloadingAndDucktypeCompatibility] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, _promote | |
| class A: pass | |
| @_promote(A) | |
| class B: pass | |
| @overload | |
| def f(n: B) -> B: | |
| return n | |
| @overload | |
| def f(n: A) -> A: | |
| return n | |
| f(B()) + 'x' # E: Unsupported left operand type for + ("B") | |
| f(A()) + 'x' # E: Unsupported left operand type for + ("A") | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadingAndIntFloatSubtyping] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| @overload | |
| def f(x: float) -> None: pass | |
| @overload | |
| def f(x: str) -> None: pass | |
| f(1.1) | |
| f('') | |
| f(1) | |
| f(()) # E: No overload variant of "f" matches argument type "tuple[()]" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(x: float) -> None \ | |
| # N: def f(x: str) -> None | |
| [builtins fixtures/primitives.pyi] | |
| [out] | |
| [case testOverloadingVariableInputs] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| @overload | |
| def f(x: int, y: int) -> None: pass | |
| @overload | |
| def f(x: int) -> None: pass | |
| f(1) | |
| f(1, 2) | |
| z = (1, 2) | |
| f(*z) | |
| [builtins fixtures/primitives.pyi] | |
| [out] | |
| [case testTypeInferenceSpecialCaseWithOverloading] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class A: | |
| def __add__(self, x: A) -> A: pass | |
| class B: | |
| def __radd__(self, x: A) -> B: pass | |
| @overload | |
| def f(x: A) -> A: pass | |
| @overload | |
| def f(x: B) -> B: pass | |
| f(A() + B())() # E: "B" not callable | |
| [case testKeywordArgOverload] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| @overload | |
| def f(x: int, y: str) -> int: pass | |
| @overload | |
| def f(x: str, y: int) -> str: pass | |
| f(x=1, y='')() # E: "int" not callable | |
| f(y=1, x='')() # E: "str" not callable | |
| [case testIgnoreOverloadVariantBasedOnKeywordArg] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| @overload | |
| def f(x: int) -> int: pass | |
| @overload | |
| def f(y: int) -> str: pass | |
| f(x=1)() # E: "int" not callable | |
| f(y=1)() # E: "str" not callable | |
| [case testOverloadWithTupleVarArg] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| @overload | |
| def f(x: int, y: str) -> int: pass | |
| @overload | |
| def f(*x: str) -> str: pass | |
| f(*(1,))() # E: No overload variant of "f" matches argument type "tuple[int]" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(x: int, y: str) -> int \ | |
| # N: def f(*x: str) -> str | |
| f(*('',))() # E: "str" not callable | |
| f(*(1, ''))() # E: "int" not callable | |
| f(*(1, '', 1))() # E: No overload variant of "f" matches argument type "tuple[int, str, int]" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(x: int, y: str) -> int \ | |
| # N: def f(*x: str) -> str | |
| [builtins fixtures/tuple.pyi] | |
| [case testPreferExactSignatureMatchInOverload] | |
| # flags: --no-strict-optional | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, List | |
| @overload | |
| def f(x: int, y: List[int] = None) -> int: pass | |
| @overload | |
| def f(x: int, y: List[str] = None) -> int: pass | |
| f(y=[1], x=0)() # E: "int" not callable | |
| f(y=[''], x=0)() # E: "int" not callable | |
| a = f(y=[['']], x=0) # E: List item 0 has incompatible type "list[str]"; expected "int" | |
| reveal_type(a) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadWithDerivedFromAny] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import Any, overload | |
| Base = None # type: Any | |
| class C: | |
| @overload | |
| def __init__(self, a: str) -> None: pass | |
| @overload | |
| def __init__(self, a: int) -> None: pass | |
| class Derived(Base): | |
| def to_dict(self) -> C: | |
| return C(self) # fails without the fix for #1363 | |
| C(Derived()) # fails without the hack | |
| C(Base()) # Always ok | |
| [case testOverloadWithBoundedTypeVar] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, TypeVar | |
| T = TypeVar('T', bound=str) | |
| @overload | |
| def f(x: T) -> T: pass | |
| @overload | |
| def f(x: int) -> bool: pass | |
| class mystr(str): pass | |
| f('x')() # E: "str" not callable | |
| f(1)() # E: "bool" not callable | |
| f(1.1) # E: No overload variant of "f" matches argument type "float" \ | |
| # N: Possible overload variants: \ | |
| # N: def [T: str] f(x: T) -> T \ | |
| # N: def f(x: int) -> bool | |
| f(mystr())() # E: "mystr" not callable | |
| [builtins fixtures/primitives.pyi] | |
| [case testOverloadedCallWithVariableTypes] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, TypeVar, List | |
| T = TypeVar('T', bound=str) | |
| @overload | |
| def f(x: T) -> T: pass | |
| @overload | |
| def f(x: List[T]) -> None: pass | |
| class mystr(str): pass | |
| U = TypeVar('U', bound=mystr) | |
| V = TypeVar('V') | |
| def g(x: U, y: V) -> None: | |
| f(x)() # E: "mystr" not callable | |
| f(y) # E: No overload variant of "f" matches argument type "V" \ | |
| # N: Possible overload variants: \ | |
| # N: def [T: str] f(x: T) -> T \ | |
| # N: def [T: str] f(x: list[T]) -> None | |
| a = f([x]) | |
| reveal_type(a) # N: Revealed type is "None" | |
| f([y]) # E: Value of type variable "T" of "f" cannot be "V" | |
| f([x, y]) # E: Value of type variable "T" of "f" cannot be "object" | |
| [builtins fixtures/list.pyi] | |
| [out] | |
| [case testOverloadOverlapWithTypeVars] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, TypeVar, Sequence, List | |
| T = TypeVar('T', bound=str) | |
| @overload | |
| def f(x: Sequence[T]) -> None: pass | |
| @overload | |
| def f(x: Sequence[int]) -> int: pass | |
| @overload | |
| def g(x: Sequence[T]) -> None: pass | |
| @overload | |
| def g(x: Sequence[str]) -> int: pass # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader | |
| @overload | |
| 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 | |
| @overload | |
| def i(x: List[T]) -> None: pass | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadOverlapWithTypeVarsWithValues] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, TypeVar | |
| AnyStr = TypeVar('AnyStr', bytes, str) | |
| @overload | |
| def f(x: int) -> int: pass | |
| @overload | |
| def f(x: AnyStr) -> str: pass | |
| f(1)() # E: "int" not callable | |
| f('1')() # E: "str" not callable | |
| f(b'1')() # E: "str" not callable | |
| f(1.0) # E: No overload variant of "f" matches argument type "float" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(x: int) -> int \ | |
| # N: def [AnyStr: (bytes, str)] f(x: AnyStr) -> str | |
| @overload | |
| def g(x: AnyStr, *a: AnyStr) -> None: pass | |
| @overload | |
| def g(x: int, *a: AnyStr) -> None: pass | |
| g('foo') | |
| g('foo', 'bar') | |
| g('foo', b'bar') # E: Value of type variable "AnyStr" of "g" cannot be "Sequence[object]" | |
| g(1) | |
| g(1, 'foo') | |
| g(1, 'foo', b'bar') # E: Value of type variable "AnyStr" of "g" cannot be "Sequence[object]" | |
| [builtins fixtures/primitives.pyi] | |
| [case testOverloadOverlapWithTypeVarsWithValuesOrdering] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, TypeVar | |
| AnyStr = TypeVar('AnyStr', bytes, str) | |
| @overload | |
| def f(x: AnyStr) -> AnyStr: pass | |
| @overload | |
| def f(x: str) -> str: pass # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader | |
| @overload | |
| def g(x: str) -> str: pass | |
| @overload | |
| def g(x: AnyStr) -> AnyStr: pass | |
| [builtins fixtures/primitives.pyi] | |
| [case testOverloadsUsingAny] | |
| from typing import overload, List, Any, Union | |
| @overload | |
| def foo(x: List[int]) -> int: ... | |
| @overload | |
| def foo(x: List[str]) -> str: ... | |
| def foo(x): pass | |
| a: List[int] | |
| b: List[str] | |
| c: List[Any] | |
| d: Union[List[int], List[str]] | |
| e: List[bool] | |
| f: List[object] | |
| g: List[Union[int, str]] | |
| reveal_type(foo(a)) | |
| reveal_type(foo(b)) | |
| reveal_type(foo(c)) | |
| reveal_type(foo(d)) | |
| foo(e) | |
| foo(f) | |
| foo(g) | |
| [builtins fixtures/list.pyi] | |
| [out] | |
| main:17: note: Revealed type is "builtins.int" | |
| main:18: note: Revealed type is "builtins.str" | |
| main:19: note: Revealed type is "Any" | |
| main:20: note: Revealed type is "builtins.int | builtins.str" | |
| main:21: error: Argument 1 to "foo" has incompatible type "list[bool]"; expected "list[int]" | |
| main:21: note: "list" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance | |
| main:21: note: Consider using "Sequence" instead, which is covariant | |
| main:22: error: Argument 1 to "foo" has incompatible type "list[object]"; expected "list[int]" | |
| main:23: error: Argument 1 to "foo" has incompatible type "list[int | str]"; expected "list[int]" | |
| [case testOverloadAgainstEmptyCollections] | |
| from typing import overload, List | |
| @overload | |
| def f(x: List[int]) -> int: ... | |
| @overload | |
| def f(x: List[str]) -> str: ... | |
| def f(x): pass | |
| reveal_type(f([])) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadAgainstEmptyCovariantCollections] | |
| from typing import overload, TypeVar, Generic | |
| T = TypeVar('T', covariant=True) | |
| class Wrapper(Generic[T]): pass | |
| class A: pass | |
| class B(A): pass | |
| class C: pass | |
| @overload | |
| def f(x: Wrapper[A]) -> int: ... | |
| @overload | |
| def f(x: Wrapper[C]) -> str: ... | |
| def f(x): pass | |
| reveal_type(f(Wrapper())) # N: Revealed type is "builtins.int" | |
| reveal_type(f(Wrapper[C]())) # N: Revealed type is "builtins.str" | |
| reveal_type(f(Wrapper[B]())) # N: Revealed type is "builtins.int" | |
| [case testOverlappingOverloadCounting] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| class A: pass | |
| class B(A): pass | |
| @overload | |
| def f(x: int) -> None: pass | |
| @overload | |
| def f(x: B) -> str: pass # E: Overloaded function signatures 2 and 3 overlap with incompatible return types | |
| @overload | |
| def f(x: A) -> int: pass | |
| [case testOverloadWithTupleMatchingTypeVar] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import TypeVar, Generic, Tuple, overload | |
| T = TypeVar('T') | |
| class A(Generic[T]): | |
| @overload | |
| def f(self, arg: T) -> None: | |
| pass | |
| @overload | |
| def f(self, arg: T, default: int) -> None: | |
| pass | |
| b = A() # type: A[Tuple[int, int]] | |
| b.f((0, 0)) | |
| b.f((0, '')) # E: Argument 1 to "f" of "A" has incompatible type "tuple[int, str]"; expected "tuple[int, int]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testSingleOverloadStub] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| @overload | |
| def f(a: int) -> None: pass | |
| def f(a: int) -> None: pass | |
| [out] | |
| tmp/foo.pyi:2: error: Single overload definition, multiple required | |
| tmp/foo.pyi:4: error: An implementation for an overloaded function is not allowed in a stub file | |
| [case testSingleOverload2] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| def f(a: int) -> None: pass | |
| @overload | |
| def f(a: str) -> None: pass | |
| [out] | |
| tmp/foo.pyi:3: error: Name "f" already defined on line 2 | |
| tmp/foo.pyi:3: error: Single overload definition, multiple required | |
| [case testNonconsecutiveOverloads] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| @overload | |
| def f(a: int) -> None: pass | |
| 1 | |
| @overload | |
| def f(a: str) -> None: pass | |
| [out] | |
| tmp/foo.pyi:2: error: Single overload definition, multiple required | |
| tmp/foo.pyi:5: error: Name "f" already defined on line 2 | |
| tmp/foo.pyi:5: error: Single overload definition, multiple required | |
| [case testNonconsecutiveOverloadsMissingFirstOverload] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| def f(a: int) -> None: pass | |
| 1 | |
| @overload | |
| def f(a: str) -> None: pass | |
| [out] | |
| tmp/foo.pyi:4: error: Name "f" already defined on line 2 | |
| tmp/foo.pyi:4: error: Single overload definition, multiple required | |
| [case testNonconsecutiveOverloadsMissingLaterOverload] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| @overload | |
| def f(a: int) -> None: pass | |
| 1 | |
| def f(a: str) -> None: pass | |
| [out] | |
| tmp/foo.pyi:2: error: Single overload definition, multiple required | |
| tmp/foo.pyi:5: error: Name "f" already defined on line 2 | |
| [case testOverloadTuple] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, Tuple | |
| @overload | |
| def f(x: int, y: Tuple[str, ...]) -> None: pass | |
| @overload | |
| def f(x: int, y: str) -> None: pass | |
| f(1, ('2', '3')) | |
| f(1, (2, '3')) # E: Argument 2 to "f" has incompatible type "tuple[int, str]"; expected "tuple[str, ...]" | |
| f(1, ('2',)) | |
| f(1, '2') | |
| f(1, (2, 3)) # E: Argument 2 to "f" has incompatible type "tuple[int, int]"; expected "tuple[str, ...]" | |
| x = ('2', '3') # type: Tuple[str, ...] | |
| f(1, x) | |
| y = (2, 3) # type: Tuple[int, ...] | |
| f(1, y) # E: Argument 2 to "f" has incompatible type "tuple[int, ...]"; expected "tuple[str, ...]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testCallableSpecificOverload] | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload, Callable | |
| @overload | |
| def f(a: Callable[[], int]) -> None: pass | |
| @overload | |
| def f(a: str) -> None: pass | |
| f(0) # E: No overload variant of "f" matches argument type "int" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(a: Callable[[], int]) -> None \ | |
| # N: def f(a: str) -> None | |
| [case testCustomRedefinitionDecorator] | |
| from typing import Any, Callable, Type | |
| class Chain(object): | |
| def chain(self, function: Callable[[Any], int]) -> 'Chain': | |
| return self | |
| class Test(object): | |
| do_chain = Chain() | |
| @do_chain.chain # E: Name "do_chain" already defined on line 9 | |
| def do_chain(self) -> int: | |
| return 2 | |
| @do_chain.chain # E: Name "do_chain" already defined on line 11 | |
| def do_chain(self) -> int: | |
| return 3 | |
| t = Test() | |
| reveal_type(t.do_chain) # N: Revealed type is "__main__.Chain" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument1] | |
| from typing import overload, Any | |
| @overload | |
| def f(x: int) -> int: ... | |
| @overload | |
| def f(x: object) -> object: ... | |
| def f(x): pass | |
| a: Any | |
| reveal_type(f(a)) # N: Revealed type is "Any" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument2] | |
| from typing import overload, Any | |
| @overload | |
| def f(x: int) -> int: ... | |
| @overload | |
| def f(x: float) -> float: ... | |
| def f(x): pass | |
| a: Any | |
| reveal_type(f(a)) # N: Revealed type is "Any" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument3] | |
| from typing import overload, Any | |
| @overload | |
| def f(x: int) -> int: ... | |
| @overload | |
| def f(x: str) -> str: ... | |
| def f(x): pass | |
| a: Any | |
| reveal_type(f(a)) # N: Revealed type is "Any" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument4] | |
| from typing import overload, Any | |
| @overload | |
| def f(x: int, y: int, z: str) -> int: ... | |
| @overload | |
| def f(x: object, y: int, z: str) -> object: ... | |
| def f(x): pass | |
| a: Any | |
| # Any causes ambiguity | |
| reveal_type(f(a, 1, '')) # N: Revealed type is "Any" | |
| # Any causes no ambiguity | |
| reveal_type(f(1, a, a)) # N: Revealed type is "builtins.int" | |
| reveal_type(f('', a, a)) # N: Revealed type is "builtins.object" | |
| # Like above, but use keyword arguments. | |
| reveal_type(f(y=1, z='', x=a)) # N: Revealed type is "Any" | |
| reveal_type(f(y=a, z='', x=1)) # N: Revealed type is "builtins.int" | |
| reveal_type(f(z='', x=1, y=a)) # N: Revealed type is "builtins.int" | |
| reveal_type(f(z='', x=a, y=1)) # N: Revealed type is "Any" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument5] | |
| from typing import overload, Any, Union | |
| class A: pass | |
| class B(A): pass | |
| @overload | |
| def f(x: B) -> B: ... | |
| @overload | |
| def f(x: Union[A, B]) -> A: ... | |
| def f(x): pass | |
| # Note: overloads ignore promotions so we treat 'int' and 'float' as distinct types | |
| @overload | |
| def g(x: int) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def g(x: Union[int, float]) -> float: ... | |
| def g(x): pass | |
| a: Any | |
| reveal_type(f(a)) # N: Revealed type is "Any" | |
| reveal_type(g(a)) # N: Revealed type is "Any" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument6] | |
| from typing import overload, Any | |
| @overload | |
| def f(x: int, y: int) -> int: ... | |
| @overload | |
| def f(x: float, y: int, z: str) -> float: ... | |
| @overload | |
| def f(x: object, y: int, z: str, a: None) -> str: ... | |
| def f(x): pass | |
| a: Any | |
| # Any causes ambiguity | |
| reveal_type(f(*a)) # N: Revealed type is "Any" | |
| reveal_type(f(a, *a)) # N: Revealed type is "Any" | |
| reveal_type(f(1, *a)) # N: Revealed type is "Any" | |
| reveal_type(f(1.1, *a)) # N: Revealed type is "Any" | |
| reveal_type(f('', *a)) # N: Revealed type is "builtins.str" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument7] | |
| from typing import overload, Any | |
| @overload | |
| def f(x: int, y: int, z: int) -> int: ... | |
| @overload | |
| def f(x: object, y: int, z: int) -> object: ... | |
| def f(x): pass | |
| @overload | |
| def g(x: int, y: int, z: int) -> int: ... | |
| @overload | |
| def g(x: object, y: int, z: str) -> object: ... | |
| def g(x): pass | |
| a: Any | |
| reveal_type(f(1, *a)) # N: Revealed type is "builtins.int" | |
| reveal_type(g(1, *a)) # N: Revealed type is "Any" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument8] | |
| from typing import overload, Any | |
| @overload | |
| def f(x: int, y: int, z: int) -> str: ... | |
| @overload | |
| def f(x: object, y: int, z: int) -> str: ... | |
| def f(x): pass | |
| a: Any | |
| # The return type is not ambiguous so Any arguments cause no ambiguity. | |
| reveal_type(f(a, 1, 1)) # N: Revealed type is "builtins.str" | |
| reveal_type(f(1, *a)) # N: Revealed type is "builtins.str" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument9] | |
| from typing import overload, Any, List | |
| @overload | |
| def f(x: List[int]) -> List[int]: ... | |
| @overload | |
| def f(x: List[Any]) -> List[Any]: ... | |
| def f(x): pass | |
| a: Any | |
| b: List[Any] | |
| c: List[str] | |
| d: List[int] | |
| reveal_type(f(a)) # N: Revealed type is "builtins.list[Any]" | |
| reveal_type(f(b)) # N: Revealed type is "builtins.list[Any]" | |
| reveal_type(f(c)) # N: Revealed type is "builtins.list[Any]" | |
| reveal_type(f(d)) # N: Revealed type is "builtins.list[builtins.int]" | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadWithOverlappingItemsAndAnyArgument10] | |
| from typing import overload, Any | |
| @overload | |
| def f(*, x: int = 3, y: int = 3) -> int: ... | |
| @overload | |
| def f(**kwargs: str) -> str: ... | |
| def f(*args, **kwargs): pass | |
| a: Any | |
| i: int | |
| reveal_type(f(x=a, y=i)) # N: Revealed type is "builtins.int" | |
| reveal_type(f(y=a)) # N: Revealed type is "Any" | |
| reveal_type(f(x=a, y=a)) # N: Revealed type is "Any" | |
| [builtins fixtures/dict.pyi] | |
| [case testOverloadWithOverlappingItemsAndAnyArgument11] | |
| from typing import overload, Any, Dict | |
| @overload | |
| def f(x: int = 3, **kwargs: int) -> int: ... | |
| @overload | |
| def f(**kwargs: str) -> str: ... | |
| def f(*args, **kwargs): pass | |
| a: Dict[str, Any] | |
| i: int | |
| reveal_type(f(x=i, **a)) # N: Revealed type is "builtins.int" | |
| reveal_type(f(**a)) # N: Revealed type is "Any" | |
| [builtins fixtures/dict.pyi] | |
| [case testOverloadWithOverlappingItemsAndAnyArgument12] | |
| from typing import overload, Any | |
| @overload | |
| def f(x: int) -> Any: ... | |
| @overload | |
| def f(x: str) -> str: ... | |
| def f(x): pass | |
| a: Any | |
| reveal_type(f(a)) # N: Revealed type is "Any" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument13] | |
| from typing import Any, overload, TypeVar, Generic | |
| class slice: pass | |
| T = TypeVar('T') | |
| class A(Generic[T]): | |
| @overload | |
| def f(self, x: int) -> T: ... | |
| @overload | |
| def f(self, x: slice) -> A[T]: ... | |
| def f(self, x): ... | |
| i: Any | |
| a: A[Any] | |
| reveal_type(a.f(i)) # N: Revealed type is "Any" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument14] | |
| from typing import Any, overload, TypeVar, Generic | |
| T = TypeVar('T') | |
| class Wrapper(Generic[T]): pass | |
| class slice: pass | |
| class A(Generic[T]): | |
| @overload | |
| def f(self, x: int) -> Wrapper[T]: ... | |
| @overload | |
| def f(self, x: slice) -> Wrapper[A[T]]: ... | |
| def f(self, x): ... | |
| i: Any | |
| a: A[Any] | |
| reveal_type(a.f(i)) # N: Revealed type is "__main__.Wrapper[Any]" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument15] | |
| from typing import overload, Any, Union | |
| @overload | |
| def f(x: int) -> str: ... | |
| @overload | |
| def f(x: str) -> str: ... | |
| def f(x): pass | |
| @overload | |
| def g(x: int) -> Union[str, int]: ... | |
| @overload | |
| def g(x: str) -> Union[int, str]: ... | |
| def g(x): pass | |
| a: Any | |
| reveal_type(f(a)) # N: Revealed type is "builtins.str" | |
| reveal_type(g(a)) # N: Revealed type is "builtins.str | builtins.int" | |
| [case testOverloadWithOverlappingItemsAndAnyArgument16] | |
| from typing import overload, Any, Union, Callable | |
| @overload | |
| def f(x: int) -> Callable[[int, int], int]: ... | |
| @overload | |
| def f(x: str) -> Callable[[str], str]: ... | |
| def f(x): pass | |
| a: Any | |
| reveal_type(f(a)) # N: Revealed type is "def (*Any, **Any) -> Any" | |
| reveal_type(f(a)(a)) # N: Revealed type is "Any" | |
| [case testOverloadOnOverloadWithType] | |
| from typing import Any, Type, TypeVar, overload | |
| from mod import MyInt | |
| T = TypeVar('T') | |
| @overload | |
| def make(cls: Type[T]) -> T: pass | |
| @overload | |
| def make() -> Any: pass | |
| def make(*args): | |
| pass | |
| c = make(MyInt) | |
| reveal_type(c) # N: Revealed type is "mod.MyInt" | |
| [file mod.pyi] | |
| from typing import overload | |
| class MyInt: | |
| @overload | |
| def __init__(self, x: str) -> None: pass | |
| @overload | |
| def __init__(self, x: str, y: int) -> None: pass | |
| [builtins fixtures/tuple.pyi] | |
| [out] | |
| [case testOverloadTupleInstance] | |
| from typing import overload, Tuple, Any | |
| class A: ... | |
| class A1(A): ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| @overload | |
| def f(x: A) -> A: ... | |
| @overload | |
| def f(x: Tuple[C]) -> B: ... | |
| @overload | |
| def f(x: Tuple[A1, int]) -> C: ... # E: Overloaded function signatures 3 and 5 overlap with incompatible return types | |
| @overload | |
| def f(x: Tuple[A, str]) -> D: ... | |
| @overload | |
| def f(x: Tuple[A, int]) -> D: ... | |
| @overload | |
| def f(x: Tuple[()]) -> D: ... | |
| def f(x: Any) -> Any:... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadTupleEllipsisNumargs] | |
| from typing import overload, Tuple, Any | |
| class A: ... | |
| class B: ... | |
| @overload | |
| def r1(x: Tuple[()]) -> B: ... # E: Overloaded function signatures 1 and 4 overlap with incompatible return types | |
| @overload | |
| def r1(x: Tuple[A]) -> B: ... # E: Overloaded function signatures 2 and 4 overlap with incompatible return types | |
| @overload | |
| def r1(x: Tuple[A, A]) -> B: ... # E: Overloaded function signatures 3 and 4 overlap with incompatible return types | |
| @overload | |
| def r1(x: Tuple[A, ...]) -> A: ... | |
| def r1(x: Any) -> Any: ... | |
| @overload | |
| def r2(x: Tuple[A, ...]) -> A: ... | |
| @overload | |
| def r2(x: Tuple[A, A]) -> B: ... # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader | |
| @overload | |
| def r2(x: Tuple[A]) -> B: ... # E: Overloaded function signature 3 will never be matched: signature 1's parameter type(s) are the same or broader | |
| @overload | |
| def r2(x: Tuple[()]) -> B: ... # E: Overloaded function signature 4 will never be matched: signature 1's parameter type(s) are the same or broader | |
| def r2(x: Any) -> Any: ... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadTupleEllipsisVariance] | |
| from typing import overload, Tuple, Any | |
| class A: ... | |
| class A1(A): ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| @overload | |
| def r(x: Tuple[A1, ...]) -> A: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def r(x: Tuple[A, ...]) -> B: ... | |
| @overload | |
| def r(x: Tuple[B, ...]) -> C: ... | |
| def r(x: Any) -> Any:... | |
| @overload | |
| def g(x: A) -> A: ... | |
| @overload | |
| def g(x: Tuple[A1, ...]) -> B: ... # E: Overloaded function signatures 2 and 3 overlap with incompatible return types | |
| @overload | |
| def g(x: Tuple[A, A]) -> C: ... | |
| @overload | |
| def g(x: Tuple[A, B]) -> D: ... | |
| def g(x: Any) -> Any:... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadWithMethodOverrideAndImplementation] | |
| from typing import overload, Union, Any | |
| class Parent: | |
| @overload | |
| def f(self, arg: int) -> int: ... | |
| @overload | |
| def f(self, arg: str) -> str: ... | |
| def f(self, arg: Any) -> Any: ... | |
| class Child1(Parent): | |
| @overload | |
| def f(self, arg: int) -> int: ... | |
| @overload | |
| def f(self, arg: str) -> str: ... | |
| def f(self, arg: Union[int, str]) -> Union[int, str]: ... | |
| class Child2(Parent): | |
| @overload | |
| def f(self, arg: int) -> int: ... | |
| @overload | |
| def f(self, arg: str) -> str: ... | |
| def f(self, arg: Union[int, str]) -> int: ... # E: Overloaded function implementation cannot produce return type of signature 2 | |
| class Child3(Parent): | |
| @overload | |
| def f(self, arg: int) -> int: ... | |
| @overload | |
| def f(self, arg: str) -> str: ... | |
| def f(self, arg: Any) -> Any: ... | |
| class Child4(Parent): | |
| @overload | |
| def f(self, arg: int) -> int: ... | |
| @overload | |
| def f(self, arg: str) -> str: ... | |
| def f(self, arg: Union[int, str]) -> Union[int, str]: | |
| return b'' # E: Incompatible return value type (got "bytes", expected "int | str") | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadWithIncompatibleMethodOverrideAndImplementation] | |
| from typing import overload, Union, Any | |
| class StrSub: pass | |
| class ParentWithTypedImpl: | |
| @overload | |
| def f(self, arg: int) -> int: ... | |
| @overload | |
| def f(self, arg: str) -> str: ... | |
| def f(self, arg: Union[int, str]) -> Union[int, str]: ... | |
| class Child1(ParentWithTypedImpl): | |
| @overload # Fail | |
| def f(self, arg: int) -> int: ... | |
| @overload | |
| def f(self, arg: StrSub) -> str: ... | |
| def f(self, arg: Union[int, StrSub]) -> Union[int, str]: ... | |
| class Child2(ParentWithTypedImpl): | |
| @overload # Fail | |
| def f(self, arg: int) -> int: ... | |
| @overload | |
| def f(self, arg: StrSub) -> str: ... | |
| def f(self, arg: Any) -> Any: ... | |
| class ParentWithDynamicImpl: | |
| @overload | |
| def f(self, arg: int) -> int: ... | |
| @overload | |
| def f(self, arg: str) -> str: ... | |
| def f(self, arg: Any) -> Any: ... | |
| class Child3(ParentWithDynamicImpl): | |
| @overload # Fail | |
| def f(self, arg: int) -> int: ... | |
| @overload | |
| def f(self, arg: StrSub) -> str: ... | |
| def f(self, arg: Union[int, StrSub]) -> Union[int, str]: ... | |
| class Child4(ParentWithDynamicImpl): | |
| @overload # Fail | |
| def f(self, arg: int) -> int: ... | |
| @overload | |
| def f(self, arg: StrSub) -> str: ... | |
| def f(self, arg: Any) -> Any: ... | |
| [builtins fixtures/tuple.pyi] | |
| [out] | |
| main:13: error: Signature of "f" incompatible with supertype "ParentWithTypedImpl" | |
| main:13: note: Superclass: | |
| main:13: note: @overload | |
| main:13: note: def f(self, arg: int) -> int | |
| main:13: note: @overload | |
| main:13: note: def f(self, arg: str) -> str | |
| main:13: note: Subclass: | |
| main:13: note: @overload | |
| main:13: note: def f(self, arg: int) -> int | |
| main:13: note: @overload | |
| main:13: note: def f(self, arg: StrSub) -> str | |
| main:20: error: Signature of "f" incompatible with supertype "ParentWithTypedImpl" | |
| main:20: note: Superclass: | |
| main:20: note: @overload | |
| main:20: note: def f(self, arg: int) -> int | |
| main:20: note: @overload | |
| main:20: note: def f(self, arg: str) -> str | |
| main:20: note: Subclass: | |
| main:20: note: @overload | |
| main:20: note: def f(self, arg: int) -> int | |
| main:20: note: @overload | |
| main:20: note: def f(self, arg: StrSub) -> str | |
| main:34: error: Signature of "f" incompatible with supertype "ParentWithDynamicImpl" | |
| main:34: note: Superclass: | |
| main:34: note: @overload | |
| main:34: note: def f(self, arg: int) -> int | |
| main:34: note: @overload | |
| main:34: note: def f(self, arg: str) -> str | |
| main:34: note: Subclass: | |
| main:34: note: @overload | |
| main:34: note: def f(self, arg: int) -> int | |
| main:34: note: @overload | |
| main:34: note: def f(self, arg: StrSub) -> str | |
| main:41: error: Signature of "f" incompatible with supertype "ParentWithDynamicImpl" | |
| main:41: note: Superclass: | |
| main:41: note: @overload | |
| main:41: note: def f(self, arg: int) -> int | |
| main:41: note: @overload | |
| main:41: note: def f(self, arg: str) -> str | |
| main:41: note: Subclass: | |
| main:41: note: @overload | |
| main:41: note: def f(self, arg: int) -> int | |
| main:41: note: @overload | |
| main:41: note: def f(self, arg: StrSub) -> str | |
| [case testOverloadAnyIsConsideredValidReturnSubtype] | |
| from typing import Any, overload, Optional | |
| @overload | |
| def foo(x: None) -> Any: ... | |
| @overload | |
| def foo(x: Optional[str]) -> str: ... | |
| def foo(x): pass | |
| @overload | |
| def bar(x: None) -> object: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def bar(x: Optional[str]) -> str: ... | |
| def bar(x): pass | |
| [case testOverloadWithNonPositionalArgs] | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| @overload | |
| def foo(*, p1: A, p2: B = B()) -> A: ... | |
| @overload | |
| def foo(*, p2: B = B()) -> B: ... | |
| def foo(p1, p2=None): ... | |
| reveal_type(foo()) # N: Revealed type is "__main__.B" | |
| reveal_type(foo(p2=B())) # N: Revealed type is "__main__.B" | |
| reveal_type(foo(p1=A())) # N: Revealed type is "__main__.A" | |
| [case testOverloadWithNonPositionalArgsIgnoresOrder] | |
| from typing import overload | |
| class A: ... | |
| class B(A): ... | |
| class X: ... | |
| class Y: ... | |
| @overload | |
| def f(*, p1: X, p2: A) -> X: ... | |
| @overload | |
| def f(*, p2: B, p1: X) -> Y: ... # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader | |
| def f(*, p1, p2): ... | |
| @overload | |
| def g(*, p1: X, p2: B) -> X: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def g(*, p2: A, p1: X) -> Y: ... | |
| def g(*, p1, p2): ... | |
| [case testOverloadWithVariableArgsAreOverlapping] | |
| 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: ... | |
| @overload | |
| def foo1(x: int, y: int, z: int) -> str: ... | |
| @overload | |
| 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: ... | |
| @overload | |
| def bar1(*x: int) -> int: ... | |
| @overload | |
| def bar2(x: int, y: str, z: int) -> str: ... | |
| @overload | |
| def bar2(*x: int) -> int: ... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadDetectsPossibleMatchesWithGenerics] | |
| # flags: --strict-optional | |
| from typing import overload, TypeVar, Generic, Optional, List | |
| T = TypeVar('T') | |
| # The examples below are unsafe, but it is a quite common pattern | |
| # so we ignore the possibility of type variables taking value `None` | |
| # for the purpose of overload overlap checks. | |
| @overload | |
| def foo(x: None, y: None) -> str: ... | |
| @overload | |
| def foo(x: T, y: T) -> int: ... | |
| def foo(x): ... | |
| oi: Optional[int] | |
| reveal_type(foo(None, None)) # N: Revealed type is "builtins.str" | |
| reveal_type(foo(None, 42)) # N: Revealed type is "builtins.int" | |
| reveal_type(foo(42, 42)) # N: Revealed type is "builtins.int" | |
| reveal_type(foo(oi, None)) # N: Revealed type is "builtins.int | builtins.str" | |
| reveal_type(foo(oi, 42)) # N: Revealed type is "builtins.int" | |
| reveal_type(foo(oi, oi)) # N: Revealed type is "builtins.int | builtins.str" | |
| @overload | |
| def foo_list(x: None) -> None: ... | |
| @overload | |
| def foo_list(x: T) -> List[T]: ... | |
| def foo_list(x): ... | |
| reveal_type(foo_list(oi)) # N: Revealed type is "builtins.list[builtins.int] | None" | |
| # What if 'T' is 'object'? | |
| @overload | |
| def bar(x: None, y: int) -> str: ... | |
| @overload | |
| def bar(x: T, y: T) -> int: ... | |
| def bar(x, y): ... | |
| class Wrapper(Generic[T]): | |
| @overload | |
| def foo(self, x: None, y: None) -> str: ... | |
| @overload | |
| def foo(self, x: T, y: None) -> int: ... | |
| def foo(self, x): ... | |
| @overload | |
| def bar(self, x: None, y: int) -> str: ... | |
| @overload | |
| def bar(self, x: T, y: T) -> int: ... | |
| def bar(self, x, y): ... | |
| @overload | |
| def baz(x: str, y: str) -> str: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def baz(x: T, y: T) -> int: ... | |
| def baz(x): ... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadFlagsPossibleMatches] | |
| from wrapper import * | |
| [file wrapper.pyi] | |
| from typing import overload | |
| @overload | |
| def foo1(x: str) -> str: ... | |
| @overload | |
| def foo1(x: str, y: str = ...) -> int: ... | |
| @overload | |
| def foo2(x: str, y: str = ...) -> int: ... | |
| @overload | |
| def foo2(x: str) -> str: ... # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader | |
| @overload | |
| def foo3(x: str) -> str: ... | |
| @overload | |
| def foo3(x: str, y: str) -> int: ... | |
| [case testOverloadPossibleOverlapWithArgsAndKwargs] | |
| from wrapper import * | |
| [file wrapper.pyi] | |
| from typing import overload | |
| @overload | |
| def foo1(*args: int) -> int: ... | |
| @overload | |
| def foo1(**kwargs: int) -> str: ... | |
| @overload | |
| def foo2(**kwargs: int) -> str: ... | |
| @overload | |
| def foo2(*args: int) -> int: ... | |
| [builtins fixtures/dict.pyi] | |
| [case testOverloadPossibleOverlapWithVarargs] | |
| from wrapper import * | |
| [file wrapper.pyi] | |
| from typing import overload | |
| @overload | |
| def foo1(*args: int) -> int: ... | |
| @overload | |
| def foo1(*args2: int) -> str: ... # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader | |
| @overload | |
| def foo2(*args: int) -> str: ... | |
| @overload | |
| def foo2(*args2: str) -> int: ... | |
| @overload | |
| def foo3(*args: int) -> str: ... | |
| @overload | |
| def foo3(*args: str) -> int: ... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadPossibleOverlapWithVarargs2] | |
| from wrapper import * | |
| [file wrapper.pyi] | |
| from typing import overload | |
| @overload | |
| def foo1(*args: str) -> int: ... | |
| @overload | |
| def foo1(x: int, *args2: int) -> str: ... | |
| @overload | |
| 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: ... | |
| @overload | |
| def foo3(x: int, *args2: int) -> str: ... | |
| @overload | |
| def foo4(x: int, *args: int) -> str: ... | |
| @overload | |
| def foo4(*args2: int) -> int: ... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadPossibleOverlapWithVarargs3] | |
| from wrapper import * | |
| [file wrapper.pyi] | |
| from typing import overload | |
| class Other: ... | |
| @overload | |
| def foo1(x: Other, *args: int) -> str: ... | |
| @overload | |
| def foo1(*args: str) -> int: ... | |
| @overload | |
| def foo2(*args: int) -> str: ... | |
| @overload | |
| def foo2(x: Other, *args: str) -> int: ... | |
| @overload | |
| def foo3(x: Other = ..., *args: int) -> str: ... | |
| @overload | |
| def foo3(*args: str) -> int: ... | |
| @overload | |
| def foo4(*args: int) -> str: ... | |
| @overload | |
| def foo4(x: Other = ..., *args: str) -> int: ... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadPossibleOverlapWithVarargs4] | |
| from typing import overload | |
| @overload | |
| 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: ... | |
| @overload | |
| def foo2(x: int = 0, y: int = 0) -> int: ... | |
| def foo2(*args): pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadPossibleOverlapWithKwargs] | |
| from wrapper import * | |
| [file wrapper.pyi] | |
| from typing import overload | |
| @overload | |
| def foo1(**kwargs: int) -> int: ... | |
| @overload | |
| def foo1(**kwargs2: int) -> str: ... # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader | |
| @overload | |
| def foo2(**kwargs: int) -> str: ... | |
| @overload | |
| def foo2(**kwargs2: str) -> int: ... | |
| @overload | |
| def foo(**kwargs: int) -> str: ... | |
| @overload | |
| def foo(**kwargs: str) -> int: ... | |
| [builtins fixtures/dict.pyi] | |
| [case testOverloadPossibleOverlapMixingNamedArgsWithVarargs] | |
| from wrapper import * | |
| [file wrapper.pyi] | |
| from typing import overload | |
| @overload | |
| def foo1(x: str, *, y: str) -> str: ... | |
| @overload | |
| def foo1(*x: str) -> int: ... | |
| @overload | |
| def foo2(*x: str) -> int: ... | |
| @overload | |
| def foo2(x: str, *, y: str) -> str: ... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadPossibleOverlapMixingOptionalArgsWithVarargs] | |
| from wrapper import * | |
| [file wrapper.pyi] | |
| from typing import overload | |
| @overload | |
| def foo1(x: str, y: str = ..., z: str = ...) -> str: ... | |
| @overload | |
| def foo1(*x: str) -> int: ... | |
| @overload | |
| def foo2(*x: str) -> int: ... | |
| @overload | |
| def foo2(x: str, y: str = ..., z: str = ...) -> str: ... | |
| @overload | |
| def foo3(x: int, y: str = ..., z: str = ...) -> str: ... | |
| @overload | |
| def foo3(*x: str) -> int: ... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadPossibleOverlapMixingOptionalArgsWithVarargs2] | |
| from wrapper import * | |
| [file wrapper.pyi] | |
| from typing import overload | |
| @overload | |
| 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: ... | |
| @overload | |
| def foo2(*x: str) -> int: ... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadPossibleOverlapMixingNamedArgsWithKwargs] | |
| from wrapper import * | |
| [file wrapper.pyi] | |
| from typing import overload | |
| @overload | |
| def foo1(*, x: str, y: str, z: str) -> str: ... | |
| @overload | |
| def foo1(**x: str) -> int: ... | |
| @overload | |
| def foo2(**x: str) -> int: ... | |
| @overload | |
| def foo2(*, x: str, y: str, z: str) -> str: ... # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader | |
| @overload | |
| def foo3(*, x: int, y: str, z: str) -> str: ... | |
| @overload | |
| def foo3(*x: str) -> int: ... | |
| [builtins fixtures/dict.pyi] | |
| [case testOverloadPossibleOverlapMixingNamedArgsWithKwargs2] | |
| from wrapper import * | |
| [file wrapper.pyi] | |
| from typing import overload | |
| @overload | |
| def foo1(*, x: str, y: str, z: int) -> str: ... | |
| @overload | |
| def foo1(**x: str) -> int: ... | |
| @overload | |
| def foo2(**x: str) -> int: ... | |
| @overload | |
| def foo2(*, x: str, y: str, z: int) -> str: ... | |
| @overload | |
| def foo3(*, x: str, y: str, z: int = ...) -> str: ... | |
| @overload | |
| def foo3(**x: str) -> int: ... | |
| @overload | |
| def foo4(**x: str) -> int: ... | |
| @overload | |
| def foo4(*, x: str, y: str, z: int = ...) -> str: ... | |
| [builtins fixtures/dict.pyi] | |
| [case testOverloadPossibleOverlapMixingNamedArgsWithKwargs3] | |
| from wrapper import * | |
| [file wrapper.pyi] | |
| 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 \ | |
| # N: Flipping the order of overloads will fix this error | |
| @overload | |
| def foo1(**x: str) -> int: ... | |
| @overload | |
| def foo2(**x: str) -> int: ... | |
| @overload | |
| def foo2(x: str, *, y: str, z: str) -> str: ... | |
| [builtins fixtures/dict.pyi] | |
| [case testOverloadVarargInputAndVarargDefinition] | |
| from typing import overload, List | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| @overload | |
| def foo(x: int) -> A: ... | |
| @overload | |
| def foo(x: int, y: int) -> B: ... | |
| @overload | |
| def foo(x: int, y: int, z: int, *args: int) -> C: ... | |
| def foo(*args): pass | |
| reveal_type(foo(1)) # N: Revealed type is "__main__.A" | |
| reveal_type(foo(1, 2)) # N: Revealed type is "__main__.B" | |
| reveal_type(foo(1, 2, 3)) # N: Revealed type is "__main__.C" | |
| reveal_type(foo(*[1])) # N: Revealed type is "__main__.C" | |
| reveal_type(foo(*[1, 2])) # N: Revealed type is "__main__.C" | |
| reveal_type(foo(*[1, 2, 3])) # N: Revealed type is "__main__.C" | |
| x: List[int] | |
| reveal_type(foo(*x)) # N: Revealed type is "__main__.C" | |
| y: List[str] | |
| foo(*y) # E: No overload variant of "foo" matches argument type "list[str]" \ | |
| # N: Possible overload variants: \ | |
| # N: def foo(x: int) -> A \ | |
| # N: def foo(x: int, y: int) -> B \ | |
| # N: def foo(x: int, y: int, z: int, *args: int) -> C | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadMultipleVarargDefinition] | |
| from typing import overload, List, Any | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| @overload | |
| def foo(x: int) -> A: ... | |
| @overload | |
| def foo(x: int, y: int) -> B: ... | |
| @overload | |
| def foo(x: int, y: int, z: int, *args: int) -> C: ... | |
| @overload | |
| def foo(*x: str) -> D: ... | |
| def foo(*args): pass | |
| reveal_type(foo(*[1, 2])) # N: Revealed type is "__main__.C" | |
| reveal_type(foo(*["a", "b"])) # N: Revealed type is "__main__.D" | |
| x: List[Any] | |
| reveal_type(foo(*x)) # N: Revealed type is "Any" | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadMultipleVarargDefinitionComplex] | |
| from typing import TypeVar, overload, Any, Callable | |
| T1 = TypeVar('T1') | |
| T2 = TypeVar('T2') | |
| T3 = TypeVar('T3') | |
| @overload | |
| def chain_call(input_value: T1, | |
| f1: Callable[[T1], T2]) -> T2: ... | |
| @overload | |
| def chain_call(input_value: T1, | |
| f1: Callable[[T1], T2], | |
| f2: Callable[[T2], T3]) -> T3: ... | |
| @overload | |
| def chain_call(input_value: T1, | |
| *f_rest: Callable[[T1], T1]) -> T1: ... | |
| @overload | |
| def chain_call(input_value: T1, | |
| f1: Callable[[T1], T2], | |
| f2: Callable[[T2], T3], | |
| f3: Callable[[T3], Any], | |
| *f_rest: Callable[[Any], Any]) -> Any: ... | |
| def chain_call(input_value, *f_rest): | |
| for function in f_rest: | |
| input_value = function(input_value) | |
| return input_value | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| def f(x: A) -> A: ... | |
| def f1(x: A) -> B: ... | |
| def f2(x: B) -> C: ... | |
| def f3(x: C) -> D: ... | |
| reveal_type(chain_call(A(), f1, f2)) # N: Revealed type is "__main__.C" | |
| reveal_type(chain_call(A(), f1, f2, f3)) # N: Revealed type is "Any" | |
| reveal_type(chain_call(A(), f, f, f, f)) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadVarargsSelection] | |
| from typing import overload, Tuple | |
| @overload | |
| def f(x: int) -> Tuple[int]: ... | |
| @overload | |
| def f(x: int, y: int) -> Tuple[int, int]: ... | |
| @overload | |
| def f(*xs: int) -> Tuple[int, ...]: ... | |
| def f(*args): pass | |
| i: int | |
| reveal_type(f(i)) # N: Revealed type is "tuple[builtins.int]" | |
| reveal_type(f(i, i)) # N: Revealed type is "tuple[builtins.int, builtins.int]" | |
| reveal_type(f(i, i, i)) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| reveal_type(f(*[])) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| reveal_type(f(*[i])) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| reveal_type(f(*[i, i])) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| reveal_type(f(*[i, i, i])) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadVarargsSelectionWithTuples] | |
| from typing import overload, Tuple | |
| @overload | |
| def f(x: int) -> Tuple[int]: ... | |
| @overload | |
| def f(x: int, y: int) -> Tuple[int, int]: ... | |
| @overload | |
| def f(*xs: int) -> Tuple[int, ...]: ... | |
| def f(*args): pass | |
| i: int | |
| reveal_type(f(*())) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| reveal_type(f(*(i,))) # N: Revealed type is "tuple[builtins.int]" | |
| reveal_type(f(*(i, i))) # N: Revealed type is "tuple[builtins.int, builtins.int]" | |
| reveal_type(f(*(i, i, i))) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadVarargsSelectionWithNamedTuples] | |
| from typing import overload, Tuple, NamedTuple | |
| @overload | |
| def f(x: int, y: int) -> Tuple[int, int]: ... | |
| @overload | |
| def f(*xs: int) -> Tuple[int, ...]: ... | |
| def f(*args): pass | |
| A = NamedTuple('A', [('x', int), ('y', int)]) | |
| B = NamedTuple('B', [('a', int), ('b', int)]) | |
| C = NamedTuple('C', [('a', int), ('b', int), ('c', int)]) | |
| a: A | |
| b: B | |
| c: C | |
| reveal_type(f(*a)) # N: Revealed type is "tuple[builtins.int, builtins.int]" | |
| reveal_type(f(*b)) # N: Revealed type is "tuple[builtins.int, builtins.int]" | |
| reveal_type(f(*c)) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadKwargsSelectionWithDict] | |
| from typing import overload, Tuple, Dict | |
| @overload | |
| def f(*, x: int) -> Tuple[int]: ... | |
| @overload | |
| def f(*, x: int, y: int) -> Tuple[int, int]: ... | |
| @overload | |
| def f(**xs: int) -> Tuple[int, ...]: ... | |
| def f(**kwargs): pass | |
| empty: Dict[str, int] | |
| reveal_type(f(**empty)) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| reveal_type(f(**{'x': 4})) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| reveal_type(f(**{'x': 4, 'y': 4})) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| reveal_type(f(**{'a': 4, 'b': 4, 'c': 4})) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| [builtins fixtures/dict.pyi] | |
| [case testOverloadKwargsSelectionWithTypedDict] | |
| from typing import overload, Tuple, TypedDict | |
| @overload | |
| def f(*, x: int) -> Tuple[int]: ... | |
| @overload | |
| def f(*, x: int, y: int) -> Tuple[int, int]: ... | |
| @overload | |
| def f(**xs: int) -> Tuple[int, ...]: ... | |
| def f(**args): pass | |
| A = TypedDict('A', {'x': int}) | |
| B = TypedDict('B', {'x': int, 'y': int}) | |
| C = TypedDict('C', {'x': int, 'y': int, 'z': int}) | |
| a: A | |
| b: B | |
| c: C | |
| reveal_type(f(**a)) # N: Revealed type is "tuple[builtins.int]" | |
| reveal_type(f(**b)) # N: Revealed type is "tuple[builtins.int, builtins.int]" | |
| reveal_type(f(**c)) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testOverloadVarargsAndKwargsSelection] | |
| from typing import overload, Any, Tuple, Dict | |
| class A: pass | |
| class B(A): pass | |
| @overload | |
| def f(x: int, y: int) -> B: pass | |
| @overload | |
| def f(x: int, y: int, **kwargs: int) -> A: pass | |
| @overload | |
| def f(*args: int, **kwargs: int) -> Any: pass | |
| def f(*args, **kwargs): pass | |
| a: Tuple[int, int] | |
| b: Tuple[int, ...] | |
| c: Dict[str, int] | |
| reveal_type(f(*a, **c)) # N: Revealed type is "__main__.A" | |
| reveal_type(f(*b, **c)) # N: Revealed type is "__main__.A" | |
| reveal_type(f(*a)) # N: Revealed type is "__main__.B" | |
| reveal_type(f(*b)) # N: Revealed type is "Any" | |
| # TODO: Should this be 'Any' instead? | |
| # The first matching overload with a kwarg is f(int, int, **int) -> A, | |
| # but f(*int, **int) -> Any feels like a better fit. | |
| reveal_type(f(**c)) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/args.pyi] | |
| [case testOverloadWithPartiallyOverlappingUnions] | |
| from typing import overload, Union | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| @overload | |
| def f(x: Union[A, B]) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: Union[B, C]) -> str: ... | |
| def f(x): ... | |
| @overload | |
| def g(x: Union[A, B]) -> int: ... | |
| @overload | |
| def g(x: Union[B, C]) -> int: ... | |
| def g(x): ... | |
| @overload | |
| def h(x: Union[A, B]) -> int: ... | |
| @overload | |
| def h(x: Union[C, D]) -> str: ... | |
| def h(x): ... | |
| @overload | |
| def i(x: Union[A, B]) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def i(x: Union[A, B, C]) -> str: ... | |
| def i(x): ... | |
| [case testOverloadWithPartiallyOverlappingUnionsNested] | |
| from typing import overload, Union, List | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| @overload | |
| def f(x: List[Union[A, B]]) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: List[Union[B, C]]) -> str: ... | |
| def f(x): ... | |
| @overload | |
| def g(x: List[Union[A, B]]) -> int: ... | |
| @overload | |
| def g(x: List[Union[B, C]]) -> int: ... | |
| def g(x): ... | |
| @overload | |
| def h(x: List[Union[A, B]]) -> int: ... | |
| @overload | |
| def h(x: List[Union[C, D]]) -> str: ... | |
| def h(x): ... | |
| @overload | |
| def i(x: List[Union[A, B]]) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types \ | |
| # N: Flipping the order of overloads will fix this error | |
| @overload | |
| def i(x: List[Union[A, B, C]]) -> str: ... | |
| def i(x): ... | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadPartialOverlapWithUnrestrictedTypeVar] | |
| from typing import TypeVar, overload | |
| T = TypeVar('T') | |
| # Note: this is unsafe, but it is hard to detect. | |
| @overload | |
| def f(x: int) -> str: ... | |
| @overload | |
| def f(x: T) -> T: ... | |
| def f(x): ... | |
| @overload | |
| def g(x: int) -> int: ... | |
| @overload | |
| def g(x: T) -> T: ... | |
| def g(x): ... | |
| [case testOverloadPartialOverlapWithUnrestrictedTypeVarNested] | |
| 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: ... | |
| @overload | |
| def f1(x: List[T]) -> T: ... | |
| def f1(x): ... | |
| @overload | |
| def f2(x: List[int]) -> List[str]: ... | |
| @overload | |
| def f2(x: List[T]) -> List[T]: ... | |
| def f2(x): ... | |
| @overload | |
| def g1(x: List[int]) -> int: ... | |
| @overload | |
| def g1(x: List[T]) -> T: ... | |
| def g1(x): ... | |
| @overload | |
| def g2(x: List[int]) -> List[int]: ... | |
| @overload | |
| def g2(x: List[T]) -> List[T]: ... | |
| def g2(x): ... | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadPartialOverlapWithUnrestrictedTypeVarInClass] | |
| 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: ... | |
| @overload | |
| def f(self, x: T) -> T: ... | |
| def f(self, x): ... | |
| @overload | |
| def g(self, x: int) -> int: ... | |
| @overload | |
| def g(self, x: T) -> T: ... | |
| def g(self, x): ... | |
| [case testOverloadPartialOverlapWithUnrestrictedTypeVarInClassNested] | |
| 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: ... | |
| @overload | |
| def f1(self, x: List[T]) -> T: ... | |
| def f1(self, x): ... | |
| @overload | |
| def f2(self, x: List[int]) -> List[str]: ... | |
| @overload | |
| def f2(self, x: List[T]) -> List[T]: ... | |
| def f2(self, x): ... | |
| @overload | |
| def g1(self, x: List[int]) -> int: ... | |
| @overload | |
| def g1(self, x: List[T]) -> T: ... | |
| def g1(self, x): ... | |
| @overload | |
| def g2(self, x: List[int]) -> List[int]: ... | |
| @overload | |
| def g2(self, x: List[T]) -> List[T]: ... | |
| def g2(self, x): ... | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadTypedDictDifferentRequiredKeysMeansDictsAreDisjoint] | |
| from typing import TypedDict, overload | |
| A = TypedDict('A', {'x': int, 'y': int}) | |
| B = TypedDict('B', {'x': int, 'y': str}) | |
| @overload | |
| def f(x: A) -> int: ... | |
| @overload | |
| def f(x: B) -> str: ... | |
| def f(x): pass | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testOverloadedTypedDictPartiallyOverlappingRequiredKeys] | |
| from typing import overload, TypedDict, Union | |
| A = TypedDict('A', {'x': int, 'y': Union[int, str]}) | |
| B = TypedDict('B', {'x': int, 'y': Union[str, float]}) | |
| @overload | |
| def f(x: A) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: B) -> str: ... | |
| def f(x): pass | |
| @overload | |
| def g(x: A) -> int: ... | |
| @overload | |
| def g(x: B) -> object: ... | |
| def g(x): pass | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testOverloadedTypedDictFullyNonTotalDictsAreAlwaysPartiallyOverlapping] | |
| from typing import TypedDict, overload | |
| A = TypedDict('A', {'x': int, 'y': str}, total=False) | |
| B = TypedDict('B', {'a': bool}, total=False) | |
| C = TypedDict('C', {'x': str, 'y': int}, total=False) | |
| @overload | |
| def f(x: A) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: B) -> str: ... | |
| def f(x): pass | |
| @overload | |
| def g(x: A) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def g(x: C) -> str: ... | |
| def g(x): pass | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testOverloadedTotalAndNonTotalTypedDictsCanPartiallyOverlap] | |
| from typing import overload, TypedDict, Union | |
| A = TypedDict('A', {'x': int, 'y': str}) | |
| B = TypedDict('B', {'x': Union[int, str], 'y': str, 'z': int}, total=False) | |
| @overload | |
| def f1(x: A) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f1(x: B) -> str: ... | |
| def f1(x): pass | |
| @overload | |
| def f2(x: B) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f2(x: A) -> str: ... | |
| def f2(x): pass | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testOverloadedTypedDictsWithSomeOptionalKeysArePartiallyOverlapping] | |
| from typing import overload, TypedDict, Union | |
| class A(TypedDict): | |
| x: int | |
| y: int | |
| class B(TypedDict, total=False): | |
| z: str | |
| class C(TypedDict, total=False): | |
| z: int | |
| @overload | |
| def f(x: B) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: C) -> str: ... | |
| def f(x): pass | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testOverloadedPartiallyOverlappingInheritedTypes1] | |
| from typing import overload, List, Union, TypeVar, Generic | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| T = TypeVar('T') | |
| class ListSubclass(List[T]): pass | |
| class Unrelated(Generic[T]): pass | |
| @overload | |
| def f(x: List[Union[A, B]]) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: ListSubclass[Union[B, C]]) -> str: ... | |
| def f(x): pass | |
| @overload | |
| def g(x: List[Union[A, B]]) -> int: ... | |
| @overload | |
| def g(x: Unrelated[Union[B, C]]) -> str: ... | |
| def g(x): pass | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadedPartiallyOverlappingInheritedTypes2] | |
| from typing import overload, List, Union | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| class ListSubclass(List[Union[B, C]]): pass | |
| @overload | |
| def f(x: List[Union[A, B]]) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: ListSubclass) -> str: ... | |
| def f(x): pass | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadedPartiallyOverlappingInheritedTypes3] | |
| from typing import overload, Union, Dict, TypeVar | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| S = TypeVar('S') | |
| class DictSubclass(Dict[str, S]): pass | |
| @overload | |
| def f(x: Dict[str, Union[A, B]]) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: DictSubclass[Union[B, C]]) -> str: ... | |
| def f(x): pass | |
| [builtins fixtures/dict.pyi] | |
| [case testOverloadedPartiallyOverlappingTypeVarsAndUnion] | |
| from typing import overload, TypeVar, Union | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| S = TypeVar('S', A, B) | |
| @overload | |
| def f(x: S) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types \ | |
| # N: Flipping the order of overloads will fix this error | |
| @overload | |
| def f(x: Union[B, C]) -> str: ... | |
| def f(x): pass | |
| @overload | |
| def g(x: Union[B, C]) -> int: ... | |
| @overload | |
| def g(x: S) -> str: ... | |
| def g(x): pass | |
| [case testOverloadPartiallyOverlappingTypeVarsIdentical] | |
| from typing import overload, TypeVar, Union | |
| T = TypeVar('T') | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| @overload | |
| def f(x: T, y: T, z: Union[A, B]) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: T, y: T, z: Union[B, C]) -> str: ... | |
| def f(x, y, z): pass | |
| [case testOverloadedPartiallyOverlappingCallables] | |
| from typing import overload, Union, Callable | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| @overload | |
| def f(x: Callable[[Union[A, B]], int]) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: Callable[[Union[B, C]], int]) -> str: ... | |
| def f(x): pass | |
| [case testOverloadNotConfusedForProperty] | |
| from typing import overload | |
| class PropertyClass: | |
| @property | |
| def foo(self) -> str: return "..." | |
| @foo.setter | |
| def foo(self, value: str) -> None: pass | |
| @foo.deleter | |
| def foo(self) -> None: pass | |
| class OverloadClass: | |
| @overload | |
| def foo(self) -> str: pass | |
| @overload | |
| def foo(self, value: str) -> None: pass | |
| @overload | |
| def foo(self) -> None: pass # E: Overloaded function signature 3 will never be matched: signature 1's parameter type(s) are the same or broader | |
| def foo(self, *args): pass | |
| [builtins fixtures/property.pyi] | |
| [case testOverloadInferUnionReturnBasic] | |
| from typing import overload, Union | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| @overload | |
| def f1(x: A) -> B: ... | |
| @overload | |
| def f1(x: C) -> D: ... | |
| def f1(x): ... | |
| arg1: Union[A, C] | |
| reveal_type(f1(arg1)) # N: Revealed type is "__main__.B | __main__.D" | |
| arg2: Union[A, B] | |
| f1(arg2) # E: Argument 1 to "f1" has incompatible type "A | B"; expected "A" | |
| @overload | |
| def f2(x: A) -> B: ... | |
| @overload | |
| def f2(x: C) -> B: ... | |
| def f2(x): ... | |
| reveal_type(f2(arg1)) # N: Revealed type is "__main__.B" | |
| [case testOverloadInferUnionReturnMultipleArguments] | |
| from typing import overload, Union | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| @overload | |
| def f1(x: A, y: C) -> B: ... | |
| @overload | |
| def f1(x: C, y: A) -> D: ... | |
| def f1(x, y): ... | |
| arg1: Union[A, C] | |
| reveal_type(f1(arg1, arg1)) | |
| @overload | |
| def f2(x: A, y: C) -> B: ... | |
| @overload | |
| def f2(x: C, y: C) -> D: ... | |
| def f2(x, y): ... | |
| reveal_type(f2(arg1, arg1)) | |
| reveal_type(f2(arg1, C())) | |
| [out] | |
| main:15: note: Revealed type is "__main__.B" | |
| main:15: error: Argument 1 to "f1" has incompatible type "A | C"; expected "A" | |
| main:15: error: Argument 2 to "f1" has incompatible type "A | C"; expected "C" | |
| main:23: note: Revealed type is "__main__.B" | |
| main:23: error: Argument 1 to "f2" has incompatible type "A | C"; expected "A" | |
| main:23: error: Argument 2 to "f2" has incompatible type "A | C"; expected "C" | |
| main:24: note: Revealed type is "__main__.B | __main__.D" | |
| [case testOverloadInferUnionRespectsVariance] | |
| from typing import overload, TypeVar, Union, Generic | |
| class A: pass | |
| class B(A): pass | |
| class C(B): pass | |
| T_co = TypeVar('T_co', covariant=True) | |
| T_contra = TypeVar('T_contra', contravariant=True) | |
| class WrapperCo(Generic[T_co]): pass | |
| class WrapperContra(Generic[T_contra]): pass | |
| @overload | |
| def foo(x: WrapperCo[B]) -> int: ... | |
| @overload | |
| def foo(x: WrapperContra[B]) -> str: ... | |
| def foo(x): pass | |
| compat: Union[WrapperCo[C], WrapperContra[A]] | |
| reveal_type(foo(compat)) # N: Revealed type is "builtins.int | builtins.str" | |
| not_compat: Union[WrapperCo[A], WrapperContra[C]] | |
| foo(not_compat) # E: Argument 1 to "foo" has incompatible type "WrapperCo[A] | WrapperContra[C]"; expected "WrapperCo[B]" | |
| [case testOverloadInferUnionIfParameterNamesAreDifferent] | |
| from typing import overload, Union | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| @overload | |
| def f(x: A) -> B: ... | |
| @overload | |
| def f(y: B) -> C: ... | |
| def f(x): ... | |
| x: Union[A, B] | |
| reveal_type(f(A())) # N: Revealed type is "__main__.B" | |
| reveal_type(f(B())) # N: Revealed type is "__main__.C" | |
| reveal_type(f(x)) # N: Revealed type is "__main__.B | __main__.C" | |
| [case testOverloadInferUnionReturnFunctionsWithKwargs] | |
| from typing import overload, Union, Optional | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D(B, C): ... | |
| @overload | |
| def f(x: A) -> D: ... | |
| @overload | |
| def f(x: A, y: Optional[B] = None) -> C: ... | |
| @overload | |
| def f(x: A, z: Optional[C] = None) -> B: ... | |
| def f(x, y=None, z=None): ... | |
| reveal_type(f(A(), B())) # N: Revealed type is "__main__.C" | |
| reveal_type(f(A(), C())) # N: Revealed type is "__main__.B" | |
| arg: Union[B, C] | |
| reveal_type(f(A(), arg)) # N: Revealed type is "__main__.C | __main__.B" | |
| reveal_type(f(A())) # N: Revealed type is "__main__.D" | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadInferUnionWithDifferingLengths] | |
| from typing import overload, Union | |
| class Parent: ... | |
| class Child(Parent): ... | |
| class A: ... | |
| class B: ... | |
| @overload | |
| def f(x: A) -> Child: ... | |
| @overload | |
| def f(x: B, y: B = B()) -> Parent: ... | |
| def f(*args): ... | |
| x: Union[A, B] | |
| reveal_type(f(x)) # N: Revealed type is "__main__.Parent" | |
| f(x, B()) # E: Argument 1 to "f" has incompatible type "A | B"; expected "B" | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadInferUnionWithMixOfPositionalAndOptionalArgs] | |
| from typing import overload, Union, Optional | |
| class A: ... | |
| class B: ... | |
| @overload | |
| def f(x: A) -> int: ... | |
| @overload | |
| def f(x: Optional[B] = None) -> str: ... | |
| def f(*args): ... | |
| x: Union[A, B] | |
| y: Optional[A] | |
| z: Union[A, Optional[B]] | |
| reveal_type(f(x)) # N: Revealed type is "builtins.int | builtins.str" | |
| reveal_type(f(y)) # N: Revealed type is "builtins.int | builtins.str" | |
| reveal_type(f(z)) # N: Revealed type is "builtins.int | builtins.str" | |
| reveal_type(f()) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadingInferUnionReturnWithTypevarWithValueRestriction] | |
| from typing import overload, Union, TypeVar, Generic | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| T = TypeVar('T', B, C) | |
| class Wrapper(Generic[T]): | |
| @overload | |
| def f(self, x: T) -> B: ... | |
| @overload | |
| def f(self, x: A) -> C: ... | |
| def f(self, x): ... | |
| obj: Wrapper[B] = Wrapper() | |
| x: Union[A, B] | |
| reveal_type(obj.f(A())) # N: Revealed type is "__main__.C" | |
| reveal_type(obj.f(B())) # N: Revealed type is "__main__.B" | |
| reveal_type(obj.f(x)) # N: Revealed type is "__main__.C | __main__.B" | |
| [case testOverloadingInferUnionReturnWithFunctionTypevarReturn] | |
| from typing import overload, Union, TypeVar, Generic | |
| T = TypeVar('T') | |
| class W1(Generic[T]): pass | |
| class W2(Generic[T]): pass | |
| class A: pass | |
| class B: pass | |
| @overload | |
| def foo(x: W1[T]) -> T: ... | |
| @overload | |
| def foo(x: W2[T]) -> T: ... | |
| def foo(x): ... | |
| def bar(x: Union[W1[T], W2[T]]) -> T: ... | |
| def wrapper() -> None: | |
| obj1: Union[W1[A], W2[A]] | |
| a1: A = foo(obj1) | |
| a2 = foo(obj1) | |
| reveal_type(a1) # N: Revealed type is "__main__.A" | |
| reveal_type(a2) # N: Revealed type is "__main__.A" | |
| obj2: Union[W1[A], W2[B]] | |
| reveal_type(foo(obj2)) # N: Revealed type is "__main__.A | __main__.B" | |
| bar(obj2) # E: Cannot infer value of type parameter "T" of "bar" | |
| b1_overload: A = foo(obj2) # E: Incompatible types in assignment (expression has type "A | B", variable has type "A") | |
| b1_union: A = bar(obj2) # E: Cannot infer value of type parameter "T" of "bar" | |
| [case testOverloadingInferUnionReturnWithObjectTypevarReturn] | |
| from typing import overload, Union, TypeVar, Generic | |
| T = TypeVar('T') | |
| class W1(Generic[T]): pass | |
| class W2(Generic[T]): pass | |
| class A: pass | |
| class B: pass | |
| class SomeType(Generic[T]): | |
| @overload | |
| def foo(self, x: W1[T]) -> T: ... | |
| @overload | |
| def foo(self, x: W2[T]) -> T: ... | |
| def foo(self, x): ... | |
| def bar(self, x: Union[W1[T], W2[T]]) -> T: ... | |
| def wrapper() -> None: | |
| obj1: Union[W1[A], W2[A]] | |
| a1 = SomeType[A]().foo(obj1) | |
| reveal_type(a1) # N: Revealed type is "__main__.A" | |
| # Note: These should be fine, but mypy has an unrelated bug | |
| # that makes them error out? | |
| a2_overload: A = SomeType().foo(obj1) # E: Argument 1 to "foo" of "SomeType" has incompatible type "W1[A] | W2[A]"; expected "W1[Never]" | |
| a2_union: A = SomeType().bar(obj1) # E: Argument 1 to "bar" of "SomeType" has incompatible type "W1[A] | W2[A]"; expected "W1[Never] | W2[Never]" | |
| SomeType().foo(obj1) # E: Argument 1 to "foo" of "SomeType" has incompatible type "W1[A] | W2[A]"; expected "W1[Never]" | |
| SomeType().bar(obj1) # E: Argument 1 to "bar" of "SomeType" has incompatible type "W1[A] | W2[A]"; expected "W1[Never] | W2[Never]" | |
| [case testOverloadingInferUnionReturnWithBadObjectTypevarReturn] | |
| from typing import overload, Union, TypeVar, Generic | |
| T = TypeVar('T') | |
| class W1(Generic[T]): pass | |
| class W2(Generic[T]): pass | |
| class A: pass | |
| class B: pass | |
| class SomeType(Generic[T]): | |
| @overload | |
| def foo(self, x: W1[T]) -> T: ... | |
| @overload | |
| def foo(self, x: W2[T]) -> T: ... | |
| def foo(self, x): ... | |
| def bar(self, x: Union[W1[T], W2[T]]) -> T: ... | |
| def wrapper(mysterious: T) -> T: | |
| obj1: Union[W1[A], W2[B]] | |
| SomeType().foo(obj1) # E: Argument 1 to "foo" of "SomeType" has incompatible type "W1[A] | W2[B]"; expected "W1[Never]" | |
| SomeType().bar(obj1) # E: Argument 1 to "bar" of "SomeType" has incompatible type "W1[A] | W2[B]"; expected "W1[Never] | W2[Never]" | |
| SomeType[A]().foo(obj1) # E: Argument 1 to "foo" of "SomeType" has incompatible type "W1[A] | W2[B]"; expected "W1[A]" | |
| SomeType[A]().bar(obj1) # E: Argument 1 to "bar" of "SomeType" has incompatible type "W1[A] | W2[B]"; expected "W1[A] | W2[A]" | |
| SomeType[T]().foo(obj1) # E: Argument 1 to "foo" of "SomeType" has incompatible type "W1[A] | W2[B]"; expected "W1[T]" | |
| SomeType[T]().bar(obj1) # E: Argument 1 to "bar" of "SomeType" has incompatible type "W1[A] | W2[B]"; expected "W1[T] | W2[T]" | |
| return mysterious | |
| [case testOverloadingInferUnionReturnWithMixedTypevars] | |
| from typing import overload, Generic, TypeVar, List, Tuple, Union | |
| class A: pass | |
| class B(A): pass | |
| class C(A): pass | |
| T = TypeVar('T', bound=A) | |
| S = TypeVar('S') | |
| class Dummy(Generic[T]): | |
| @overload | |
| def foo(self, x: List[Tuple[T, S]], y: S) -> T: ... | |
| @overload | |
| def foo(self, x: List[S], y: S) -> S: ... | |
| def foo(self, x: Union[List[Tuple[T, S]], List[S]], y: S) -> Union[T, S]: ... | |
| T1 = TypeVar('T1', bound=A) | |
| def t_is_same_bound(arg1: T1, arg2: S) -> Tuple[T1, S]: | |
| x1: Union[List[S], List[Tuple[T1, S]]] | |
| y1: S | |
| reveal_type(Dummy[T1]().foo(x1, y1)) # N: Revealed type is "S`-2 | T1`-1" | |
| x2: Union[List[T1], List[Tuple[T1, T1]]] | |
| y2: T1 | |
| reveal_type(Dummy[T1]().foo(x2, y2)) # N: Revealed type is "T1`-1" | |
| return arg1, arg2 | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadingInferUnionReturnWithMixedTypevarsInnerMismatch] | |
| from typing import overload, Generic, TypeVar, List, Tuple, Union | |
| class A: pass | |
| class B(A): pass | |
| class C(A): pass | |
| T = TypeVar('T', bound=A) | |
| S = TypeVar('S') | |
| class Dummy(Generic[T]): | |
| @overload | |
| def foo(self, x: List[Tuple[T, S]], y: S) -> T: ... | |
| @overload | |
| def foo(self, x: List[S], y: S) -> S: ... | |
| def foo(self, x: Union[List[Tuple[T, S]], List[S]], y: S) -> Union[T, S]: ... | |
| T1 = TypeVar('T1', bound=A) | |
| def t_is_same_bound(arg1: T1, arg2: S) -> Tuple[T1, S]: | |
| # The arguments in the tuple are swapped | |
| x3: Union[List[S], List[Tuple[S, T1]]] | |
| y3: S | |
| Dummy[T1]().foo(x3, y3) # E: Cannot infer value of type parameter "S" of "foo" of "Dummy" \ | |
| # E: Argument 1 to "foo" of "Dummy" has incompatible type "list[S] | list[tuple[S, T1]]"; expected "list[tuple[T1, Any]]" | |
| x4: Union[List[int], List[Tuple[C, int]]] | |
| y4: int | |
| reveal_type(Dummy[C]().foo(x4, y4)) # N: Revealed type is "builtins.int | __main__.C" | |
| Dummy[A]().foo(x4, y4) # E: Argument 1 to "foo" of "Dummy" has incompatible type "list[int] | list[tuple[C, int]]"; expected "list[tuple[A, int]]" | |
| return arg1, arg2 | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadingInferUnionReturnWithMixedTypevarsTighterBound] | |
| from typing import overload, Generic, TypeVar, List, Tuple, Union | |
| class A: pass | |
| class B(A): pass | |
| class C(A): pass | |
| T = TypeVar('T', bound=A) | |
| S = TypeVar('S') | |
| class Dummy(Generic[T]): | |
| @overload | |
| def foo(self, x: List[Tuple[T, S]], y: S) -> T: ... | |
| @overload | |
| def foo(self, x: List[S], y: S) -> S: ... | |
| def foo(self, x: Union[List[Tuple[T, S]], List[S]], y: S) -> Union[T, S]: ... | |
| T1 = TypeVar('T1', bound=B) | |
| def t_is_tighter_bound(arg1: T1, arg2: S) -> Tuple[T1, S]: | |
| x1: Union[List[S], List[Tuple[T1, S]]] | |
| y1: S | |
| reveal_type(Dummy[T1]().foo(x1, y1)) # N: Revealed type is "S`-2 | T1`-1" | |
| x2: Union[List[T1], List[Tuple[T1, T1]]] | |
| y2: T1 | |
| reveal_type(Dummy[T1]().foo(x2, y2)) # N: Revealed type is "T1`-1" | |
| return arg1, arg2 | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadingInferUnionReturnWithTypevarsAndValueRestrictions] | |
| from typing import overload, Generic, TypeVar, List, Tuple, Union | |
| class A: pass | |
| class B(A): pass | |
| class C(A): pass | |
| T = TypeVar('T', bound=A) | |
| S = TypeVar('S') | |
| class Dummy(Generic[T]): | |
| @overload | |
| def foo(self, x: List[Tuple[T, S]], y: S) -> T: ... | |
| @overload | |
| def foo(self, x: List[S], y: S) -> S: ... | |
| def foo(self, x: Union[List[Tuple[T, S]], List[S]], y: S) -> Union[T, S]: ... | |
| T3 = TypeVar('T3', B, C) | |
| def t_is_compatible_bound(arg1: T3, arg2: S) -> Tuple[T3, S]: | |
| x1: Union[List[S], List[Tuple[T3, S]]] | |
| y1: S | |
| reveal_type(Dummy[T3]().foo(x1, y1)) | |
| x2: Union[List[T3], List[Tuple[T3, T3]]] | |
| y2: T3 | |
| reveal_type(Dummy[T3]().foo(x2, y2)) | |
| return arg1, arg2 | |
| [builtins fixtures/list.pyi] | |
| [out] | |
| main:22: note: Revealed type is "S`-2 | __main__.B" | |
| main:22: note: Revealed type is "S`-2 | __main__.C" | |
| main:26: note: Revealed type is "__main__.B" | |
| main:26: note: Revealed type is "__main__.C" | |
| [case testOverloadInferUnionReturnWithInconsistentTypevarNames] | |
| from typing import overload, TypeVar, Union | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| @overload | |
| def consistent(x: T, y: str) -> T: ... | |
| @overload | |
| def consistent(x: T, y: int) -> T: ... | |
| def consistent(x: T, y: Union[str, int]) -> T: | |
| return x | |
| @overload | |
| def inconsistent(x: T, y: str) -> T: ... | |
| @overload | |
| def inconsistent(x: S, y: int) -> S: ... | |
| def inconsistent(x: T, y: Union[str, int]) -> T: | |
| return x | |
| def test(x: T) -> T: | |
| y: Union[str, int] | |
| reveal_type(consistent(x, y)) # N: Revealed type is "T`-1" | |
| # On one hand, this overload is defined in a weird way; on the other, there's technically nothing wrong with it. | |
| inconsistent(x, y) | |
| return x | |
| [case testOverloadsAndNoneWithoutStrictOptional] | |
| # flags: --no-strict-optional | |
| from typing import overload, Optional | |
| @overload | |
| def f(x: None) -> int: ... | |
| @overload | |
| def f(x: object) -> str: ... | |
| def f(x): ... | |
| # We pretend strict-optional is enabled for overload definitions, | |
| # even in non-strict optional mode | |
| @overload | |
| def g(x: None) -> int: ... | |
| @overload | |
| def g(x: int) -> str: ... | |
| def g(x): ... | |
| # Calls are still checked normally though | |
| a: None | |
| b: int | |
| c: Optional[int] | |
| reveal_type(g(a)) # N: Revealed type is "builtins.int" | |
| reveal_type(g(b)) # N: Revealed type is "builtins.str" | |
| reveal_type(g(c)) # N: Revealed type is "builtins.str" | |
| [case testOverloadsAndNoneWithStrictOptional] | |
| from typing import overload, Optional | |
| @overload | |
| def f(x: None) -> int: ... | |
| @overload | |
| def f(x: object) -> str: ... | |
| def f(x): ... | |
| @overload | |
| def g(x: None) -> int: ... | |
| @overload | |
| def g(x: int) -> str: ... | |
| def g(x): ... | |
| a: None | |
| b: int | |
| c: Optional[int] | |
| reveal_type(g(a)) # N: Revealed type is "builtins.int" | |
| reveal_type(g(b)) # N: Revealed type is "builtins.str" | |
| reveal_type(g(c)) # N: Revealed type is "builtins.str | builtins.int" | |
| [case testOverloadsNoneAndTypeVarsWithNoStrictOptional] | |
| # flags: --no-strict-optional | |
| from typing import Callable, Iterable, TypeVar, overload, Optional | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| @overload | |
| def mymap(func: None, seq: Iterable[T]) -> Iterable[T]: ... | |
| @overload | |
| def mymap(func: Callable[[T], S], seq: Iterable[T]) -> Iterable[S]: ... | |
| def mymap(*args): ... | |
| seq = [1, 2, 3] | |
| f1: Callable[[int], str] | |
| f2: None | |
| f3: Optional[Callable[[int], str]] | |
| reveal_type(mymap(f1, seq)) # N: Revealed type is "typing.Iterable[builtins.str]" | |
| reveal_type(mymap(f2, seq)) # N: Revealed type is "typing.Iterable[builtins.int]" | |
| reveal_type(mymap(f3, seq)) # N: Revealed type is "typing.Iterable[builtins.str]" | |
| [builtins fixtures/list.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadsNoneAndTypeVarsWithStrictOptional] | |
| from typing import Callable, Iterable, TypeVar, overload, Optional | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| @overload | |
| def mymap(func: None, seq: Iterable[T]) -> Iterable[T]: ... | |
| @overload | |
| def mymap(func: Callable[[T], S], seq: Iterable[T]) -> Iterable[S]: ... | |
| def mymap(*args): ... | |
| seq = [1, 2, 3] | |
| f1: Callable[[int], str] | |
| f2: None | |
| f3: Optional[Callable[[int], str]] | |
| reveal_type(mymap(f1, seq)) # N: Revealed type is "typing.Iterable[builtins.str]" | |
| reveal_type(mymap(f2, seq)) # N: Revealed type is "typing.Iterable[builtins.int]" | |
| reveal_type(mymap(f3, seq)) # N: Revealed type is "typing.Iterable[builtins.str] | typing.Iterable[builtins.int]" | |
| [builtins fixtures/list.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadsAndNoReturnNarrowTypeNoStrictOptional1] | |
| # flags: --no-strict-optional | |
| from typing import overload, Union, NoReturn | |
| @overload | |
| def narrow_int(x: str) -> NoReturn: ... | |
| @overload | |
| def narrow_int(x: int) -> int: ... | |
| def narrow_int(x: Union[int, str]) -> Union[int, NoReturn]: | |
| assert isinstance(x, int) | |
| return x | |
| def test_narrow_int() -> None: | |
| a: Union[int, str] | |
| if int(): | |
| a = narrow_int(a) | |
| reveal_type(a) # N: Revealed type is "builtins.int" | |
| b: int | |
| if int(): | |
| b = narrow_int(b) | |
| reveal_type(b) # N: Revealed type is "builtins.int" | |
| c: str | |
| if int(): | |
| c = narrow_int(c) | |
| reveal_type(c) # Note: branch is now dead, so no type is revealed | |
| # TODO: maybe we should make mypy report a warning instead? | |
| [builtins fixtures/isinstance.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadsAndNoReturnNarrowTypeWithStrictOptional1] | |
| from typing import overload, Union, NoReturn | |
| @overload | |
| def narrow_int(x: str) -> NoReturn: ... | |
| @overload | |
| def narrow_int(x: int) -> int: ... | |
| def narrow_int(x: Union[int, str]) -> Union[int, NoReturn]: | |
| assert isinstance(x, int) | |
| return x | |
| def test_narrow_int() -> None: | |
| a: Union[int, str] | |
| if int(): | |
| a = narrow_int(a) | |
| reveal_type(a) # N: Revealed type is "builtins.int" | |
| b: int | |
| if int(): | |
| b = narrow_int(b) | |
| reveal_type(b) # N: Revealed type is "builtins.int" | |
| c: str | |
| if int(): | |
| c = narrow_int(c) | |
| reveal_type(c) # Note: branch is now dead, so no type is revealed | |
| # TODO: maybe we should make mypy report a warning instead? | |
| [builtins fixtures/isinstance.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadsAndNoReturnNarrowTypeNoStrictOptional2] | |
| # flags: --no-strict-optional | |
| from typing import overload, Union, TypeVar, NoReturn, Optional | |
| T = TypeVar('T') | |
| @overload | |
| def narrow_none(x: None) -> NoReturn: ... | |
| @overload | |
| def narrow_none(x: T) -> T: ... | |
| def narrow_none(x: Optional[T]) -> Union[NoReturn, T]: | |
| assert x is not None | |
| return x | |
| def test_narrow_none() -> None: | |
| a: Optional[int] | |
| if int(): | |
| a = narrow_none(a) | |
| reveal_type(a) # N: Revealed type is "builtins.int" | |
| b: int | |
| if int(): | |
| b = narrow_none(b) | |
| reveal_type(b) # N: Revealed type is "builtins.int" | |
| c: None | |
| if int(): | |
| c = narrow_none(c) | |
| reveal_type(c) # Note: branch is now dead, so no type is revealed | |
| [builtins fixtures/isinstance.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadsAndNoReturnNarrowTypeWithStrictOptional2] | |
| from typing import overload, Union, TypeVar, NoReturn, Optional | |
| T = TypeVar('T') | |
| @overload | |
| def narrow_none(x: None) -> NoReturn: ... | |
| @overload | |
| def narrow_none(x: T) -> T: ... | |
| def narrow_none(x: Optional[T]) -> Union[NoReturn, T]: | |
| assert x is not None | |
| return x | |
| def test_narrow_none() -> None: | |
| a: Optional[int] | |
| if int(): | |
| a = narrow_none(a) | |
| reveal_type(a) # N: Revealed type is "builtins.int" | |
| b: int | |
| if int(): | |
| b = narrow_none(b) | |
| reveal_type(b) # N: Revealed type is "builtins.int" | |
| c: None | |
| if int(): | |
| c = narrow_none(c) | |
| reveal_type(c) # Branch is now dead | |
| [builtins fixtures/isinstance.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadsAndNoReturnNarrowTypeNoStrictOptional3] | |
| # flags: --no-strict-optional | |
| from typing import overload, TypeVar, NoReturn, Optional | |
| @overload | |
| def narrow_none_v2(x: None) -> NoReturn: ... | |
| @overload | |
| def narrow_none_v2(x: T) -> T: ... | |
| def narrow_none_v2(x: Optional[T]) -> T: | |
| assert x is not None | |
| return x | |
| def test_narrow_none_v2() -> None: | |
| a: Optional[int] | |
| if int(): | |
| a = narrow_none_v2(a) | |
| reveal_type(a) # N: Revealed type is "builtins.int" | |
| b: int | |
| if int(): | |
| b = narrow_none_v2(b) | |
| reveal_type(b) # N: Revealed type is "builtins.int" | |
| c: None | |
| if int(): | |
| c = narrow_none_v2(c) | |
| reveal_type(c) # Note: branch is now dead, so no type is revealed | |
| [builtins fixtures/isinstance.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadsAndNoReturnNarrowTypeWithStrictOptional3] | |
| from typing import overload, TypeVar, NoReturn, Optional | |
| @overload | |
| def narrow_none_v2(x: None) -> NoReturn: ... | |
| @overload | |
| def narrow_none_v2(x: T) -> T: ... | |
| def narrow_none_v2(x: Optional[T]) -> T: | |
| assert x is not None | |
| return x | |
| def test_narrow_none_v2() -> None: | |
| a: Optional[int] | |
| if int(): | |
| a = narrow_none_v2(a) | |
| reveal_type(a) # N: Revealed type is "builtins.int" | |
| b: int | |
| if int(): | |
| b = narrow_none_v2(b) | |
| reveal_type(b) # N: Revealed type is "builtins.int" | |
| c: None | |
| if int(): | |
| c = narrow_none_v2(c) | |
| reveal_type(c) # Note: branch is now dead, so no type is revealed | |
| [builtins fixtures/isinstance.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadsAndNoReturnNarrowWhenBlacklistingSubtype] | |
| from typing import TypeVar, NoReturn, Union, overload | |
| class Parent: ... | |
| class A(Parent): ... | |
| class B(Parent): ... | |
| T = TypeVar('T', bound=Parent) | |
| @overload | |
| def narrow_to_not_a(x: A) -> NoReturn: ... | |
| @overload | |
| def narrow_to_not_a(x: T) -> T: ... | |
| def narrow_to_not_a(x: T) -> Union[NoReturn, T]: | |
| assert not isinstance(x, A) | |
| return x | |
| def test() -> None: | |
| val: Union[A, B] | |
| if int(): | |
| val = narrow_to_not_a(val) | |
| reveal_type(val) # N: Revealed type is "__main__.B" | |
| val2: A | |
| if int(): | |
| val2 = narrow_to_not_a(val2) | |
| reveal_type(val2) # Branch now dead | |
| [builtins fixtures/isinstance.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadsAndNoReturnNarrowWhenBlacklistingSubtype2] | |
| from typing import TypeVar, NoReturn, Union, overload | |
| class Parent: ... | |
| class A(Parent): ... | |
| class B(Parent): ... | |
| T = TypeVar('T', bound=Parent) | |
| @overload | |
| def narrow_to_not_a_v2(x: A) -> NoReturn: ... | |
| @overload | |
| def narrow_to_not_a_v2(x: T) -> T: ... | |
| def narrow_to_not_a_v2(x: T) -> T: | |
| assert not isinstance(x, A) | |
| return x | |
| def test_v2(val: Union[A, B], val2: A) -> None: | |
| if int(): | |
| val = narrow_to_not_a_v2(val) | |
| reveal_type(val) # N: Revealed type is "__main__.B" | |
| if int(): | |
| val2 = narrow_to_not_a_v2(val2) | |
| reveal_type(val2) # Branch now dead | |
| [builtins fixtures/isinstance.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadWithNonGenericDescriptor] | |
| from typing import overload, Any, Optional, Union | |
| class NumberAttribute: | |
| @overload | |
| def __get__(self, instance: None, owner: Any) -> 'NumberAttribute': ... | |
| @overload | |
| def __get__(self, instance: object, owner: Any) -> int: ... | |
| def __get__(self, instance: Optional[object], owner: Any) -> Union['NumberAttribute', int]: | |
| if instance is None: | |
| return self | |
| else: | |
| return 3 | |
| def foo(self) -> str: ... | |
| class MyModel: | |
| my_number = NumberAttribute() | |
| reveal_type(MyModel().my_number) # N: Revealed type is "builtins.int" | |
| MyModel().my_number.foo() # E: "int" has no attribute "foo" | |
| reveal_type(MyModel.my_number) # N: Revealed type is "__main__.NumberAttribute" | |
| reveal_type(MyModel.my_number.foo()) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/isinstance.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadWithNonGenericDescriptorLookalike] | |
| from typing import overload, Any, Optional, Union | |
| class FakeAttribute: | |
| @overload | |
| def dummy(self, instance: None, owner: Any) -> 'FakeAttribute': ... | |
| @overload | |
| def dummy(self, instance: object, owner: Any) -> int: ... | |
| def dummy(self, instance: Optional[object], owner: Any) -> Union['FakeAttribute', int]: ... | |
| [case testOverloadWithGenericDescriptor] | |
| from typing import overload, Any, Optional, TypeVar, Type, Union, Generic | |
| T = TypeVar('T') | |
| class NumberAttribute(Generic[T]): | |
| @overload | |
| def __get__(self, instance: None, owner: Type[T]) -> 'NumberAttribute[T]': ... | |
| @overload | |
| def __get__(self, instance: T, owner: Type[T]) -> int: ... | |
| def __get__(self, instance: Optional[T], owner: Type[T]) -> Union['NumberAttribute[T]', int]: | |
| if instance is None: | |
| return self | |
| else: | |
| return 3 | |
| def foo(self) -> str: ... | |
| class MyModel: | |
| my_number = NumberAttribute[MyModel]() | |
| reveal_type(MyModel().my_number) # N: Revealed type is "builtins.int" | |
| MyModel().my_number.foo() # E: "int" has no attribute "foo" | |
| reveal_type(MyModel.my_number) # N: Revealed type is "__main__.NumberAttribute[__main__.MyModel]" | |
| reveal_type(MyModel.my_number.foo()) # N: Revealed type is "builtins.str" | |
| reveal_type(NumberAttribute[MyModel]().__get__(None, MyModel)) # N: Revealed type is "__main__.NumberAttribute[__main__.MyModel]" | |
| reveal_type(NumberAttribute[str]().__get__(None, str)) # N: Revealed type is "__main__.NumberAttribute[builtins.str]" | |
| [builtins fixtures/isinstance.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadWithGenericDescriptorLookalike] | |
| from typing import overload, Any, Optional, TypeVar, Type, Union, Generic | |
| T = TypeVar('T') | |
| class FakeAttribute(Generic[T]): | |
| @overload | |
| def dummy(self, instance: None, owner: Type[T]) -> 'FakeAttribute[T]': ... | |
| @overload | |
| def dummy(self, instance: T, owner: Type[T]) -> int: ... | |
| def dummy(self, instance: Optional[T], owner: Type[T]) -> Union['FakeAttribute[T]', int]: ... | |
| [case testOverloadWithClassMethods] | |
| from typing import overload | |
| class Wrapper: | |
| @overload | |
| @classmethod | |
| def foo(cls, x: int) -> int: ... | |
| @overload | |
| @classmethod | |
| def foo(cls, x: str) -> str: ... | |
| @classmethod | |
| def foo(cls, x): pass | |
| reveal_type(Wrapper.foo(3)) # N: Revealed type is "builtins.int" | |
| reveal_type(Wrapper.foo("foo")) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/classmethod.pyi] | |
| [case testOverloadWithInconsistentClassMethods] | |
| from typing import overload | |
| class Wrapper1: | |
| @overload # E: Overload does not consistently use the "@classmethod" decorator on all function signatures. | |
| @classmethod | |
| def foo(cls, x: int) -> int: ... | |
| @overload | |
| @classmethod | |
| def foo(cls, x: str) -> str: ... | |
| def foo(cls, x): pass | |
| class Wrapper2: | |
| @overload # E: Overload does not consistently use the "@classmethod" decorator on all function signatures. | |
| @classmethod | |
| def foo(cls, x: int) -> int: ... | |
| @overload | |
| def foo(cls, x: str) -> str: ... | |
| @classmethod | |
| def foo(cls, x): pass | |
| class Wrapper3: | |
| @overload # E: Overload does not consistently use the "@classmethod" decorator on all function signatures. | |
| def foo(cls, x: int) -> int: ... | |
| @overload | |
| def foo(cls, x: str) -> str: ... | |
| @classmethod | |
| def foo(cls, x): pass | |
| [builtins fixtures/classmethod.pyi] | |
| [case testOverloadWithSwappedDecorators] | |
| from typing import overload | |
| class Wrapper1: | |
| @classmethod | |
| @overload | |
| def foo(cls, x: int) -> int: ... | |
| @classmethod | |
| @overload | |
| def foo(cls, x: str) -> str: ... | |
| @classmethod | |
| def foo(cls, x): pass | |
| class Wrapper2: | |
| @classmethod | |
| @overload | |
| def foo(cls, x: int) -> int: ... | |
| @overload | |
| @classmethod | |
| def foo(cls, x: str) -> str: ... | |
| @classmethod | |
| def foo(cls, x): pass | |
| class Wrapper3: | |
| @classmethod # E: Overload does not consistently use the "@classmethod" decorator on all function signatures. | |
| @overload | |
| def foo(cls, x: int) -> int: ... | |
| @overload | |
| def foo(cls, x: str) -> str: ... | |
| def foo(cls, x): pass | |
| reveal_type(Wrapper1.foo(3)) # N: Revealed type is "builtins.int" | |
| reveal_type(Wrapper2.foo(3)) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/classmethod.pyi] | |
| [case testOverloadFaultyClassMethodInheritance] | |
| from typing import overload | |
| class A: pass | |
| class B(A): pass | |
| class C(B): pass | |
| class Parent: | |
| @overload | |
| @classmethod | |
| def foo(cls, x: B) -> int: ... | |
| @overload | |
| @classmethod | |
| def foo(cls, x: str) -> str: ... | |
| @classmethod | |
| def foo(cls, x): pass | |
| class BadChild(Parent): | |
| @overload # Fail | |
| @classmethod | |
| def foo(cls, x: C) -> int: ... | |
| @overload | |
| @classmethod | |
| def foo(cls, x: str) -> str: ... | |
| @classmethod | |
| def foo(cls, x): pass | |
| class GoodChild(Parent): | |
| @overload | |
| @classmethod | |
| def foo(cls, x: A) -> int: ... | |
| @overload | |
| @classmethod | |
| def foo(cls, x: str) -> str: ... | |
| @classmethod | |
| def foo(cls, x): pass | |
| [builtins fixtures/classmethod.pyi] | |
| [out] | |
| main:20: error: Signature of "foo" incompatible with supertype "Parent" | |
| main:20: note: Superclass: | |
| main:20: note: @overload | |
| main:20: note: @classmethod | |
| main:20: note: def foo(cls, x: B) -> int | |
| main:20: note: @overload | |
| main:20: note: @classmethod | |
| main:20: note: def foo(cls, x: str) -> str | |
| main:20: note: Subclass: | |
| main:20: note: @overload | |
| main:20: note: @classmethod | |
| main:20: note: def foo(cls, x: C) -> int | |
| main:20: note: @overload | |
| main:20: note: @classmethod | |
| main:20: note: def foo(cls, x: str) -> str | |
| [case testOverloadClassMethodMixingInheritance] | |
| from typing import overload | |
| class BadParent: | |
| @overload | |
| @classmethod | |
| def foo(cls, x: int) -> int: ... | |
| @overload | |
| @classmethod | |
| def foo(cls, x: str) -> str: ... | |
| @classmethod | |
| def foo(cls, x): pass | |
| class BadChild(BadParent): | |
| @overload # Fail | |
| def foo(cls, x: int) -> int: ... | |
| @overload | |
| def foo(cls, x: str) -> str: ... | |
| def foo(cls, x): pass | |
| class GoodParent: | |
| @overload | |
| def foo(cls, x: int) -> int: ... | |
| @overload | |
| def foo(cls, x: str) -> str: ... | |
| def foo(cls, x): pass | |
| class GoodChild(GoodParent): | |
| @overload | |
| @classmethod | |
| def foo(cls, x: int) -> int: ... | |
| @overload | |
| @classmethod | |
| def foo(cls, x: str) -> str: ... | |
| @classmethod | |
| def foo(cls, x): pass | |
| [builtins fixtures/classmethod.pyi] | |
| [out] | |
| main:16: error: Signature of "foo" incompatible with supertype "BadParent" | |
| main:16: note: Superclass: | |
| main:16: note: @overload | |
| main:16: note: @classmethod | |
| main:16: note: def foo(cls, x: int) -> int | |
| main:16: note: @overload | |
| main:16: note: @classmethod | |
| main:16: note: def foo(cls, x: str) -> str | |
| main:16: note: Subclass: | |
| main:16: note: @overload | |
| main:16: note: def foo(cls, x: int) -> int | |
| main:16: note: @overload | |
| main:16: note: def foo(cls, x: str) -> str | |
| [case testOverloadClassMethodImplementation] | |
| from typing import overload, Union | |
| class Wrapper: | |
| @classmethod | |
| def other(cls) -> str: | |
| return "..." | |
| @overload | |
| @classmethod | |
| def foo(cls, x: int) -> int: ... | |
| @overload | |
| @classmethod | |
| def foo(cls, x: str) -> str: ... | |
| @classmethod # E: Overloaded function implementation cannot produce return type of signature 1 | |
| def foo(cls, x: Union[int, str]) -> str: | |
| reveal_type(cls) # N: Revealed type is "type[__main__.Wrapper]" | |
| reveal_type(cls.other()) # N: Revealed type is "builtins.str" | |
| return "..." | |
| [builtins fixtures/classmethod.pyi] | |
| [case testOverloadWithStaticMethods] | |
| from typing import overload | |
| class Wrapper: | |
| @overload | |
| @staticmethod | |
| def foo(x: int) -> int: ... | |
| @overload | |
| @staticmethod | |
| def foo(x: str) -> str: ... | |
| @staticmethod | |
| def foo(x): pass | |
| reveal_type(Wrapper.foo(3)) # N: Revealed type is "builtins.int" | |
| reveal_type(Wrapper.foo("foo")) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/staticmethod.pyi] | |
| [case testOverloadWithInconsistentStaticMethods] | |
| from typing import overload, Union | |
| class Wrapper1: | |
| @overload # E: Overload does not consistently use the "@staticmethod" decorator on all function signatures. | |
| @staticmethod | |
| def foo(x: int) -> int: ... | |
| @overload | |
| @staticmethod | |
| def foo(x: str) -> str: ... | |
| def foo(x): pass | |
| class Wrapper2: | |
| @overload # E: Overload does not consistently use the "@staticmethod" decorator on all function signatures. | |
| @staticmethod | |
| def foo(x: int) -> int: ... | |
| @overload | |
| def foo(x: str) -> str: ... # E: "self" parameter missing for a non-static method (or an invalid type for self) | |
| @staticmethod | |
| def foo(x): pass | |
| class Wrapper3: | |
| @overload # E: Overload does not consistently use the "@staticmethod" decorator on all function signatures. | |
| @staticmethod | |
| def foo(x: int) -> int: ... | |
| @overload | |
| @staticmethod | |
| def foo(x: str) -> str: ... | |
| def foo(x: Union[int, str]): pass # E: "self" parameter missing for a non-static method (or an invalid type for self) | |
| [builtins fixtures/staticmethod.pyi] | |
| [case testOverloadWithSwappedDecorators2] | |
| from typing import overload | |
| class Wrapper1: | |
| @staticmethod | |
| @overload | |
| def foo(x: int) -> int: ... | |
| @staticmethod | |
| @overload | |
| def foo(x: str) -> str: ... | |
| @staticmethod | |
| def foo(x): pass | |
| class Wrapper2: | |
| @staticmethod | |
| @overload | |
| def foo(x: int) -> int: ... | |
| @overload | |
| @staticmethod | |
| def foo(x: str) -> str: ... | |
| @staticmethod | |
| def foo(x): pass | |
| class Wrapper3: | |
| @staticmethod # E: Overload does not consistently use the "@staticmethod" decorator on all function signatures. | |
| @overload | |
| def foo(x: int) -> int: ... | |
| @overload | |
| def foo(x: str) -> str: ... # E: "self" parameter missing for a non-static method (or an invalid type for self) | |
| @staticmethod | |
| def foo(x): pass | |
| reveal_type(Wrapper1.foo(3)) # N: Revealed type is "builtins.int" | |
| reveal_type(Wrapper2.foo(3)) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/staticmethod.pyi] | |
| [case testOverloadFaultyStaticMethodInheritance] | |
| from typing import overload | |
| class A: pass | |
| class B(A): pass | |
| class C(B): pass | |
| class Parent: | |
| @overload | |
| @staticmethod | |
| def foo(x: B) -> int: ... | |
| @overload | |
| @staticmethod | |
| def foo(x: str) -> str: ... | |
| @staticmethod | |
| def foo(x): pass | |
| class BadChild(Parent): | |
| @overload # Fail | |
| @staticmethod | |
| def foo(x: C) -> int: ... | |
| @overload | |
| @staticmethod | |
| def foo(x: str) -> str: ... | |
| @staticmethod | |
| def foo(x): pass | |
| class GoodChild(Parent): | |
| @overload | |
| @staticmethod | |
| def foo(x: A) -> int: ... | |
| @overload | |
| @staticmethod | |
| def foo(x: str) -> str: ... | |
| @staticmethod | |
| def foo(x): pass | |
| [builtins fixtures/staticmethod.pyi] | |
| [out] | |
| main:20: error: Signature of "foo" incompatible with supertype "Parent" | |
| main:20: note: Superclass: | |
| main:20: note: @overload | |
| main:20: note: @staticmethod | |
| main:20: note: def foo(x: B) -> int | |
| main:20: note: @overload | |
| main:20: note: @staticmethod | |
| main:20: note: def foo(x: str) -> str | |
| main:20: note: Subclass: | |
| main:20: note: @overload | |
| main:20: note: @staticmethod | |
| main:20: note: def foo(x: C) -> int | |
| main:20: note: @overload | |
| main:20: note: @staticmethod | |
| main:20: note: def foo(x: str) -> str | |
| [case testOverloadStaticMethodMixingInheritance] | |
| from typing import overload | |
| class BadParent: | |
| @overload | |
| @staticmethod | |
| def foo(x: int) -> int: ... | |
| @overload | |
| @staticmethod | |
| def foo(x: str) -> str: ... | |
| @staticmethod | |
| def foo(x): pass | |
| class BadChild(BadParent): | |
| @overload # Fail | |
| def foo(self, x: int) -> int: ... | |
| @overload | |
| def foo(self, x: str) -> str: ... | |
| def foo(self, x): pass | |
| class GoodParent: | |
| @overload | |
| def foo(self, x: int) -> int: ... | |
| @overload | |
| def foo(self, x: str) -> str: ... | |
| def foo(self, x): pass | |
| class GoodChild(GoodParent): | |
| @overload | |
| @staticmethod | |
| def foo(x: int) -> int: ... | |
| @overload | |
| @staticmethod | |
| def foo(x: str) -> str: ... | |
| @staticmethod | |
| def foo(x): pass | |
| [builtins fixtures/staticmethod.pyi] | |
| [out] | |
| main:16: error: Signature of "foo" incompatible with supertype "BadParent" | |
| main:16: note: Superclass: | |
| main:16: note: @overload | |
| main:16: note: @staticmethod | |
| main:16: note: def foo(x: int) -> int | |
| main:16: note: @overload | |
| main:16: note: @staticmethod | |
| main:16: note: def foo(x: str) -> str | |
| main:16: note: Subclass: | |
| main:16: note: @overload | |
| main:16: note: def foo(self, x: int) -> int | |
| main:16: note: @overload | |
| main:16: note: def foo(self, x: str) -> str | |
| [case testOverloadStaticMethodImplementation] | |
| from typing import overload, Union | |
| class Wrapper: | |
| @staticmethod | |
| def other() -> str: | |
| return "..." | |
| @overload | |
| @staticmethod | |
| def foo(x: int) -> int: ... | |
| @overload | |
| @staticmethod | |
| def foo(x: str) -> str: ... | |
| @staticmethod # E: Overloaded function implementation cannot produce return type of signature 1 | |
| def foo(x: Union[int, str]) -> str: | |
| return 3 # E: Incompatible return value type (got "int", expected "str") | |
| [builtins fixtures/staticmethod.pyi] | |
| [case testUnionMathOverloadingReturnsBestType] | |
| from typing import Union, overload | |
| @overload | |
| def f(x: Union[int, str]) -> int: ... | |
| @overload | |
| def f(x: object) -> object: ... | |
| def f(x): | |
| pass | |
| x: Union[int, str] | |
| reveal_type(f(x)) # N: Revealed type is "builtins.int" | |
| [out] | |
| [case testOverloadAndSelfTypes] | |
| from typing import overload, Union, TypeVar, Type | |
| T = TypeVar('T', bound='Parent') | |
| class Parent: | |
| @overload | |
| def foo(self: T, x: int) -> T: pass | |
| @overload | |
| def foo(self, x: str) -> str: pass | |
| def foo(self: T, x: Union[int, str]) -> Union[T, str]: | |
| reveal_type(self.bar()) # N: Revealed type is "builtins.str" | |
| return self | |
| def bar(self) -> str: pass | |
| class Child(Parent): | |
| def child_only(self) -> int: pass | |
| x: Union[int, str] | |
| reveal_type(Parent().foo(3)) # N: Revealed type is "__main__.Parent" | |
| reveal_type(Child().foo(3)) # N: Revealed type is "__main__.Child" | |
| reveal_type(Child().foo("...")) # N: Revealed type is "builtins.str" | |
| reveal_type(Child().foo(x)) # N: Revealed type is "__main__.Child | builtins.str" | |
| reveal_type(Child().foo(3).child_only()) # N: Revealed type is "builtins.int" | |
| [case testOverloadAndSelfTypesGenericNoOverlap] | |
| from typing import Generic, TypeVar, Any, overload, Self, Union | |
| T = TypeVar("T") | |
| class C(Generic[T]): | |
| @overload | |
| def get(self, obj: None) -> Self: ... | |
| @overload | |
| def get(self, obj: Any) -> T: ... | |
| def get(self, obj: Union[Any, None]) -> Union[T, Self]: | |
| return self | |
| class D(C[int]): ... | |
| d: D | |
| reveal_type(d.get(None)) # N: Revealed type is "__main__.D" | |
| reveal_type(d.get("whatever")) # N: Revealed type is "builtins.int" | |
| [case testOverloadAndClassTypes] | |
| from typing import overload, Union, TypeVar, Type | |
| T = TypeVar('T', bound='Parent') | |
| class Parent: | |
| @overload | |
| @classmethod | |
| def foo(cls: Type[T], x: int) -> Type[T]: pass | |
| @overload | |
| @classmethod | |
| def foo(cls, x: str) -> str: pass | |
| @classmethod | |
| def foo(cls: Type[T], x: Union[int, str]) -> Union[Type[T], str]: | |
| reveal_type(cls.bar()) # N: Revealed type is "builtins.str" | |
| return cls | |
| @classmethod | |
| def bar(cls) -> str: pass | |
| class Child(Parent): | |
| def child_only(self) -> int: pass | |
| x: Union[int, str] | |
| reveal_type(Parent.foo(3)) # N: Revealed type is "type[__main__.Parent]" | |
| reveal_type(Child.foo(3)) # N: Revealed type is "type[__main__.Child]" | |
| reveal_type(Child.foo("...")) # N: Revealed type is "builtins.str" | |
| reveal_type(Child.foo(x)) # N: Revealed type is "type[__main__.Child] | builtins.str" | |
| reveal_type(Child.foo(3)().child_only()) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/classmethod.pyi] | |
| [case testOptionalIsNotAUnionIfNoStrictOverload] | |
| # flags: --no-strict-optional | |
| from typing import Optional, overload | |
| class B: pass | |
| class C(B): pass | |
| @overload | |
| def rp(x: C) -> C: ... | |
| @overload | |
| def rp(x: B) -> B: ... | |
| def rp(x): | |
| pass | |
| x: Optional[C] | |
| reveal_type(rp(x)) # N: Revealed type is "__main__.C" | |
| [out] | |
| [case testUnionMathTrickyOverload1] | |
| from typing import Union, overload | |
| @overload | |
| def f(x: int, y: int) -> int: ... | |
| @overload | |
| def f(x: object, y: str) -> str: ... | |
| def f(x): | |
| pass | |
| x: Union[int, str] | |
| y: Union[int, str] | |
| f(x, y) | |
| [out] | |
| main:12: error: Argument 1 to "f" has incompatible type "int | str"; expected "int" | |
| main:12: error: Argument 2 to "f" has incompatible type "int | str"; expected "int" | |
| [case testUnionMathTrickyOverload2] | |
| from typing import overload, Union, Any | |
| class C: | |
| def f(self, other: C) -> C: ... | |
| class D(C): | |
| @overload | |
| def f(self, other: D) -> D: ... | |
| @overload | |
| def f(self, other: C) -> C: ... | |
| def f(self, other): ... | |
| x: D | |
| y: Union[D, Any] | |
| reveal_type(x.f(y)) # N: Revealed type is "__main__.D | Any" | |
| [out] | |
| [case testManyUnionsInOverload] | |
| from typing import overload, TypeVar, Union | |
| T = TypeVar('T') | |
| @overload | |
| def f(x: int, y: object, z: object, t: object, u: object, w: object, v: object, s: object) -> int: ... | |
| @overload | |
| def f(x: str, y: object, z: object, t: object, u: object, w: object, v: object, s: object) -> str: ... | |
| @overload | |
| def f(x: T, y: object, z: object, t: object, u: object, w: object, v: object, s: object) -> T: ... | |
| def f(*args, **kwargs): | |
| pass | |
| class A: pass | |
| class B: pass | |
| x: Union[int, str, A, B] | |
| y = f(x, x, x, x, x, x, x, x) # 8 args | |
| reveal_type(y) # N: Revealed type is "builtins.int | builtins.str | __main__.A | __main__.B" | |
| [builtins fixtures/dict.pyi] | |
| [out] | |
| [case testOverloadsWithNoneComingSecondAreAlwaysFlaggedInNoStrictOptional] | |
| # flags: --no-strict-optional | |
| from typing import overload | |
| @overload | |
| def none_first(x: None) -> None: ... | |
| @overload | |
| def none_first(x: int) -> int: ... | |
| def none_first(x: int) -> int: | |
| return x | |
| @overload | |
| def none_second(x: int) -> int: ... | |
| @overload | |
| def none_second(x: None) -> None: ... # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader | |
| def none_second(x: int) -> int: | |
| return x | |
| [case testOverloadsWithNoneComingSecondIsOkInStrictOptional] | |
| from typing import overload, Optional | |
| @overload | |
| def none_first(x: None) -> None: ... | |
| @overload | |
| def none_first(x: int) -> int: ... | |
| def none_first(x: Optional[int]) -> Optional[int]: | |
| return x | |
| @overload | |
| def none_second(x: int) -> int: ... | |
| @overload | |
| def none_second(x: None) -> None: ... | |
| def none_second(x: Optional[int]) -> Optional[int]: | |
| return x | |
| @overload | |
| def none_loose_impl(x: None) -> None: ... | |
| @overload | |
| def none_loose_impl(x: int) -> int: ... | |
| def none_loose_impl(x: int) -> int: | |
| return x | |
| [out] | |
| main:21: error: Overloaded function implementation does not accept all possible parameters of signature 1 | |
| main:21: error: Overloaded function implementation cannot produce return type of signature 1 | |
| [case testTooManyUnionsException] | |
| from typing import overload, Union | |
| @overload | |
| def f(*args: int) -> int: ... | |
| @overload | |
| def f(*args: str) -> str: ... | |
| def f(*args): | |
| pass | |
| x: Union[int, str] | |
| f(x, x, x, x, x, x, x, x) | |
| [builtins fixtures/tuple.pyi] | |
| [out] | |
| main:11: error: Not all union combinations were tried because there are too many unions | |
| main:11: error: Argument 1 to "f" has incompatible type "int | str"; expected "int" | |
| main:11: error: Argument 2 to "f" has incompatible type "int | str"; expected "int" | |
| main:11: error: Argument 3 to "f" has incompatible type "int | str"; expected "int" | |
| main:11: error: Argument 4 to "f" has incompatible type "int | str"; expected "int" | |
| main:11: error: Argument 5 to "f" has incompatible type "int | str"; expected "int" | |
| main:11: error: Argument 6 to "f" has incompatible type "int | str"; expected "int" | |
| main:11: error: Argument 7 to "f" has incompatible type "int | str"; expected "int" | |
| main:11: error: Argument 8 to "f" has incompatible type "int | str"; expected "int" | |
| [case testSafeDunderOverlapInSubclass] | |
| from typing import overload | |
| class A: | |
| def __add__(self, x : 'A') -> 'A': ... | |
| class B(A): | |
| @overload | |
| def __add__(self, x : 'B') -> 'B': ... | |
| @overload | |
| def __add__(self, x : 'A') -> 'A' : ... | |
| def __add__(self, x): | |
| pass | |
| [out] | |
| [case testUnsafeDunderOverlapInSubclass] | |
| from typing import overload | |
| class A: | |
| def __add__(self, x : 'A') -> 'A': | |
| if isinstance(x, A): | |
| return A() | |
| else: | |
| return NotImplemented | |
| # This is unsafe override because of the problem below | |
| class B(A): | |
| @overload # Fail | |
| def __add__(self, x : 'Other') -> 'B' : ... | |
| @overload | |
| def __add__(self, x : 'A') -> 'A': ... | |
| def __add__(self, x): | |
| if isinstance(x, Other): | |
| return B() | |
| elif isinstance(x, A): | |
| return A() | |
| else: | |
| return NotImplemented | |
| class Other: | |
| def __radd__(self, x: 'A') -> 'Other': | |
| if isinstance(x, A): | |
| return Other() | |
| else: | |
| return NotImplemented | |
| actually_b: A = B() | |
| reveal_type(actually_b + Other()) # Note | |
| # Runtime type is B, this is why we report the error on overriding. | |
| [builtins fixtures/isinstance.pyi] | |
| [out] | |
| main:12: error: Signature of "__add__" incompatible with supertype "A" | |
| main:12: note: Superclass: | |
| main:12: note: def __add__(self, A, /) -> A | |
| main:12: note: Subclass: | |
| main:12: note: @overload | |
| main:12: note: def __add__(self, Other, /) -> B | |
| main:12: note: @overload | |
| main:12: note: def __add__(self, A, /) -> A | |
| main:12: note: Overloaded operator methods can't have wider argument types in overrides | |
| main:32: note: Revealed type is "__main__.Other" | |
| [case testOverloadErrorMessageManyMatches] | |
| from typing import overload | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| class D: pass | |
| @overload | |
| def f(x: A) -> None: ... | |
| @overload | |
| def f(x: B) -> None: ... | |
| @overload | |
| def f(x: C) -> None: ... | |
| @overload | |
| def f(x: D) -> None: ... | |
| @overload | |
| def f(x: int, y: int) -> None: ... | |
| def f(*args): pass | |
| f(3) # E: No overload variant of "f" matches argument type "int" \ | |
| # N: Possible overload variants: \ | |
| # N: def f(x: A) -> None \ | |
| # N: def f(x: B) -> None \ | |
| # N: def f(x: C) -> None \ | |
| # N: def f(x: D) -> None \ | |
| # N: def f(x: int, y: int) -> None | |
| @overload | |
| def g(x: A) -> None: ... | |
| @overload | |
| def g(x: B) -> None: ... | |
| @overload | |
| def g(x: C) -> None: ... | |
| def g(*args): pass | |
| g(3) # E: No overload variant of "g" matches argument type "int" \ | |
| # N: Possible overload variants: \ | |
| # N: def g(x: A) -> None \ | |
| # N: def g(x: B) -> None \ | |
| # N: def g(x: C) -> None | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadedInIter] | |
| from lib import f, g | |
| for fun in [f, g]: | |
| reveal_type(fun) # N: Revealed type is "Overload(def (x: builtins.int) -> builtins.str, def (x: builtins.str) -> builtins.int)" | |
| [file lib.pyi] | |
| from typing import overload | |
| @overload | |
| def f(x: int) -> str: ... | |
| @overload | |
| def f(x: str) -> int: ... | |
| @overload | |
| def g(x: int) -> str: ... | |
| @overload | |
| def g(x: str) -> int: ... | |
| [builtins fixtures/list.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [out] | |
| [case testNestedOverloadsNoCrash] | |
| from typing import overload | |
| def f() -> None: | |
| @overload | |
| def g(x: str) -> str: ... | |
| @overload | |
| def g(x: int) -> int: ... | |
| def g(x): | |
| pass | |
| g(str()) | |
| [out] | |
| [case testNestedOverloadsTypeVar] | |
| from typing import overload, TypeVar | |
| T = TypeVar('T') | |
| def f() -> None: | |
| @overload | |
| def g(x: str) -> str: ... | |
| @overload | |
| def g(x: T, y: int) -> T: ... | |
| def g(x): | |
| pass | |
| g(str(), str()) # E: No overload variant of "g" matches argument types "str", "str" \ | |
| # N: Possible overload variants: \ | |
| # N: def g(x: str) -> str \ | |
| # N: def [T] g(x: T, y: int) -> T | |
| reveal_type(g(str(), int())) # N: Revealed type is "builtins.str" | |
| [out] | |
| [case testNestedOverloadsTypeVarOverlap] | |
| from typing import overload, TypeVar | |
| T = TypeVar('T') | |
| def f() -> None: | |
| @overload | |
| def g(x: str) -> int: ... | |
| @overload | |
| def g(x: T) -> T: ... | |
| def g(x): | |
| pass | |
| [out] | |
| [case testNestedOverloadsMutuallyRecursive] | |
| from typing import overload, TypeVar, Dict, Any | |
| class C: ... | |
| T = TypeVar('T') | |
| def f() -> None: | |
| @overload | |
| def g() -> None: ... | |
| @overload | |
| def g(x: T) -> Dict[int, T]: ... | |
| def g(*args, **kwargs) -> Any: | |
| reveal_type(h(C())) # N: Revealed type is "builtins.dict[builtins.str, __main__.C]" | |
| @overload | |
| def h() -> None: ... | |
| @overload | |
| def h(x: T) -> Dict[str, T]: ... | |
| def h(*args, **kwargs) -> Any: | |
| reveal_type(g(C())) # N: Revealed type is "builtins.dict[builtins.int, __main__.C]" | |
| [builtins fixtures/dict.pyi] | |
| [out] | |
| [case testOverloadConstrainedTypevarNotShadowingAny] | |
| from lib import attr | |
| from typing import Any | |
| reveal_type(attr(1)) # N: Revealed type is "builtins.int" | |
| reveal_type(attr("hi")) # N: Revealed type is "builtins.int" | |
| x: Any | |
| reveal_type(attr(x)) # N: Revealed type is "Any" | |
| attr("hi", 1) # E: No overload variant of "attr" matches argument types "str", "int" \ | |
| # N: Possible overload variants: \ | |
| # N: def [T: (int, float)] attr(default: T, blah: int = ...) -> T \ | |
| # N: def attr(default: Any = ...) -> int | |
| [file lib.pyi] | |
| from typing import overload, Any, TypeVar | |
| T = TypeVar('T', int, float) | |
| @overload | |
| def attr(default: T, blah: int = ...) -> T: ... | |
| @overload | |
| def attr(default: Any = ...) -> int: ... | |
| [out] | |
| [case testOverloadBoundedTypevarNotShadowingAny] | |
| from lib import attr | |
| from typing import Any | |
| reveal_type(attr(1)) # N: Revealed type is "builtins.int" | |
| reveal_type(attr("hi")) # N: Revealed type is "builtins.int" | |
| x: Any | |
| reveal_type(attr(x)) # N: Revealed type is "Any" | |
| attr("hi", 1) # E: No overload variant of "attr" matches argument types "str", "int" \ | |
| # N: Possible overload variants: \ | |
| # N: def [T: int] attr(default: T = ..., blah: int = ...) -> T \ | |
| # N: def attr(default: Any = ...) -> int | |
| [file lib.pyi] | |
| from typing import overload, TypeVar, Any | |
| T = TypeVar('T', bound=int) | |
| @overload | |
| def attr(default: T = ..., blah: int = ...) -> T: ... | |
| @overload | |
| def attr(default: Any = ...) -> int: ... | |
| [out] | |
| [case testAnyIsOKAsFallbackInOverloads] | |
| import stub | |
| [file stub.pyi] | |
| from typing import TypeVar, Any, overload | |
| T = TypeVar('T') | |
| @overload | |
| def foo(x: T) -> T: ... | |
| @overload | |
| def foo(x: Any) -> Any: ... | |
| @overload | |
| def bar(x: T) -> T: ... | |
| @overload | |
| def bar(x: Any) -> int: ... | |
| [out] | |
| [case testOverloadsIgnorePromotions] | |
| from typing import overload, List, Union, _promote | |
| class Parent: pass | |
| class Child(Parent): pass | |
| children: List[Child] | |
| parents: List[Parent] | |
| @overload | |
| def f(x: Child) -> List[Child]: pass | |
| @overload | |
| def f(x: Parent) -> List[Parent]: pass | |
| def f(x: Union[Child, Parent]) -> Union[List[Child], List[Parent]]: | |
| if isinstance(x, Child): | |
| reveal_type(x) # N: Revealed type is "__main__.Child" | |
| return children | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.Parent" | |
| return parents | |
| ints: List[int] | |
| floats: List[float] | |
| @overload | |
| def g(x: int) -> List[int]: pass | |
| @overload | |
| def g(x: float) -> List[float]: pass | |
| def g(x: Union[int, float]) -> Union[List[int], List[float]]: | |
| if isinstance(x, int): | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| return ints | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.float" | |
| return floats | |
| [builtins fixtures/isinstancelist.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testOverloadsTypesAndUnions] | |
| from typing import overload, Type, Union | |
| class A: pass | |
| class B: pass | |
| @overload | |
| def f(x: Type[A]) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def f(x: Union[Type[A], Type[B]]) -> str: ... | |
| def f(x: Union[Type[A], Type[B]]) -> Union[int, str]: | |
| return 1 | |
| [case testBadOverloadProbableMatch] | |
| from typing import overload, List, Type | |
| class Other: pass | |
| @overload | |
| def multiple_plausible(x: int) -> int: ... | |
| @overload | |
| def multiple_plausible(x: str) -> str: ... | |
| def multiple_plausible(x): pass | |
| @overload | |
| def single_plausible(x: Type[int]) -> int: ... | |
| @overload | |
| def single_plausible(x: List[str]) -> str: ... | |
| def single_plausible(x): pass | |
| a = multiple_plausible(Other()) # E: No overload variant of "multiple_plausible" matches argument type "Other" \ | |
| # N: Possible overload variants: \ | |
| # N: def multiple_plausible(x: int) -> int \ | |
| # N: def multiple_plausible(x: str) -> str | |
| reveal_type(a) # N: Revealed type is "Any" | |
| b = single_plausible(Other) # E: Argument 1 to "single_plausible" has incompatible type "type[Other]"; expected "type[int]" | |
| reveal_type(b) # N: Revealed type is "builtins.int" | |
| c = single_plausible([Other()]) # E: List item 0 has incompatible type "Other"; expected "str" | |
| reveal_type(c) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/list.pyi] | |
| [case testDisallowUntypedDecoratorsOverload] | |
| # flags: --disallow-untyped-decorators | |
| from typing import Any, Callable, overload, TypeVar | |
| F = TypeVar('F', bound=Callable[..., Any]) | |
| @overload | |
| def dec(x: F) -> F: ... | |
| @overload | |
| def dec(x: str) -> Callable[[F], F]: ... | |
| def dec(x) -> Any: | |
| pass | |
| @dec | |
| def f(name: str) -> int: | |
| return 0 | |
| @dec('abc') | |
| def g(name: str) -> int: | |
| return 0 | |
| reveal_type(f) # N: Revealed type is "def (name: builtins.str) -> builtins.int" | |
| reveal_type(g) # N: Revealed type is "def (name: builtins.str) -> builtins.int" | |
| [case testDisallowUntypedDecoratorsOverloadDunderCall] | |
| # flags: --disallow-untyped-decorators | |
| from typing import Any, Callable, overload, TypeVar | |
| F = TypeVar('F', bound=Callable[..., Any]) | |
| class Dec: | |
| @overload | |
| def __call__(self, x: F) -> F: ... | |
| @overload | |
| def __call__(self, x: str) -> Callable[[F], F]: ... | |
| def __call__(self, x) -> Any: | |
| pass | |
| dec = Dec() | |
| @dec | |
| def f(name: str) -> int: | |
| return 0 | |
| @dec('abc') | |
| def g(name: str) -> int: | |
| return 0 | |
| reveal_type(f) # N: Revealed type is "def (name: builtins.str) -> builtins.int" | |
| reveal_type(g) # N: Revealed type is "def (name: builtins.str) -> builtins.int" | |
| [case testOverloadBadArgumentsInferredToAny1] | |
| from typing import Union, Any, overload | |
| def bar(x: int) -> Union[int, Any]: ... | |
| @overload | |
| def foo(x: str) -> None: ... | |
| @overload | |
| def foo(x: int) -> None: ... | |
| def foo(x) -> None: pass | |
| foo(bar('lol')) # E: Argument 1 to "bar" has incompatible type "str"; expected "int" | |
| [case testOverloadBadArgumentsInferredToAny2] | |
| from typing import Union, Iterable, Tuple, TypeVar, Generic, overload, Any | |
| class A: | |
| def foo(self) -> Iterable[int]: pass | |
| def bar(x: int) -> Union[A, int]: ... | |
| _T = TypeVar('_T') | |
| @overload | |
| def foo() -> None: ... | |
| @overload | |
| def foo(iterable: Iterable[_T]) -> None: ... | |
| def foo(iterable = None) -> None: pass | |
| foo(bar('lol').foo()) # E: Item "int" of "A | int" has no attribute "foo" \ | |
| # E: Argument 1 to "bar" has incompatible type "str"; expected "int" | |
| [case testOverloadInferringArgumentsUsingContext1] | |
| from typing import Optional, List, overload, TypeVar | |
| T = TypeVar('T') | |
| def g(x: Optional[T] = None) -> List[T]: ... | |
| @overload | |
| def f(x: int) -> int: ... | |
| @overload | |
| def f(x: List[int]) -> List[int]: ... | |
| def f(x): pass | |
| reveal_type(f(g())) # N: Revealed type is "builtins.list[builtins.int]" | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadInferringArgumentsUsingContext2-skip] | |
| # TODO: Overloads only use outer context to infer type variables in a given overload variant, | |
| # but never use outer context to _choose_ a better overload in ambiguous situations | |
| # like empty containers or multiple inheritance, instead just always choosing the first one. | |
| from typing import Optional, List, overload, TypeVar | |
| T = TypeVar('T') | |
| @overload | |
| def g(x: List[str]) -> List[str]: ... | |
| @overload | |
| def g(x: List[int]) -> List[int]: ... | |
| def g(x): | |
| pass | |
| @overload | |
| def f(x: int) -> int: ... | |
| @overload | |
| def f(x: List[int]) -> List[int]: ... | |
| def f(x): | |
| pass | |
| reveal_type(f(g([]))) # N: Revealed type is "builtins.list[builtins.int]" | |
| [builtins fixtures/list.pyi] | |
| [case testOverloadDeferredNode] | |
| from typing import Callable, TypeVar, Generic, Any, overload | |
| _S = TypeVar('_S') | |
| _T = TypeVar('_T') | |
| _R = TypeVar('_R') | |
| @overload | |
| def partial(__func: Callable[[_T], _S], __arg: _T) -> Callable[[], _S]: ... | |
| @overload | |
| def partial(__func: Callable[[_T, _S], _S], __arg: _T) -> Callable[[_S], _R]: ... | |
| def partial(*args: Any) -> Any: | |
| pass | |
| def f(f: Callable[[int], int]) -> None: | |
| pass | |
| def dec(f: Callable[[_S, _T], _R]) -> Callable[[_S, _T], _R]: pass | |
| def asdf() -> None: | |
| f(partial(lol, 0)) | |
| @dec | |
| def lol(x: int, y: int) -> int: | |
| pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testVeryBrokenOverload] | |
| import lib | |
| reveal_type(lib.func) # N: Revealed type is "Any" | |
| [file lib.pyi] | |
| @overload # E: Name "overload" is not defined | |
| def func(x: int) -> int: ... | |
| def func(x): # E: Name "func" already defined on line 1 | |
| return x | |
| -- Order of errors is different | |
| [case testVeryBrokenOverload2] | |
| import lib | |
| reveal_type(lib.func) # N: Revealed type is "Any" | |
| [file lib.pyi] | |
| @overload # E: Name "overload" is not defined | |
| def func(x: int) -> int: ... | |
| @overload # E: Name "func" already defined on line 1 # E: Name "overload" is not defined | |
| def func(x: str) -> str: ... | |
| [case testLiteralSubtypeOverlap] | |
| from typing import Literal, overload | |
| class MyInt(int): ... | |
| # Strictly speaking we can't prove this is unsafe (this depends on the implementation), | |
| # but such APIs seem like an anti-pattern anyways. | |
| @overload | |
| def foo(x: Literal[0]) -> None: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types | |
| @overload | |
| def foo(x: MyInt) -> int: ... | |
| def foo(x): | |
| ... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadedToGeneric] | |
| from typing import TypeVar, Callable, NewType, overload, Union | |
| # int in our stubs isn't overloaded | |
| class fakeint: | |
| @overload | |
| def __init__(self, x: Union[str, bytes] = ...) -> None: ... | |
| @overload | |
| def __init__(self, x: Union[str, bytes], base: int) -> None: ... | |
| def __init__(self, *args) -> None: pass # type: ignore | |
| U = TypeVar('U') | |
| V = TypeVar('V') | |
| W = TypeVar('W') | |
| def compose(f: Callable[[U], V], g: Callable[[W], U]) -> Callable[[W], V]: | |
| return lambda x: f(g(x)) | |
| ID = NewType("ID", fakeint) | |
| compose(ID, fakeint)("test") | |
| reveal_type(compose(ID, fakeint)) # N: Revealed type is "def (builtins.str | builtins.bytes) -> __main__.ID" | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadTwoTypeArgs] | |
| from typing import Generic, overload, TypeVar, Any | |
| T1 = TypeVar("T1") | |
| T2 = TypeVar("T2") | |
| class A: ... | |
| class B: ... | |
| class G(Generic[T1, T2]): ... | |
| @overload | |
| def f1(g: G[A, A]) -> A: ... | |
| @overload | |
| def f1(g: G[A, B]) -> B: ... | |
| def f1(g: Any) -> Any: ... | |
| @overload | |
| def f2(g: G[A, Any]) -> A: ... | |
| @overload | |
| def f2(g: G[A, B], x: int = ...) -> B: ... | |
| def f2(g: Any, x: int = ...) -> Any: ... | |
| [case testOverloadTypeVsCallable] | |
| from typing import TypeVar, Type, Callable, Any, overload, Optional | |
| class Foo: | |
| def __init__(self, **kwargs: Any): pass | |
| _T = TypeVar('_T') | |
| @overload | |
| def register(cls: Type[_T]) -> int: ... | |
| @overload | |
| def register(cls: Callable[..., _T]) -> Optional[int]: ... | |
| def register(cls: Any) -> Any: return None | |
| x = register(Foo) | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/dict.pyi] | |
| [case testOverloadWithObjectDecorator] | |
| from typing import Any, Callable, Union, overload | |
| class A: | |
| def __call__(self, *arg, **kwargs) -> None: ... | |
| def dec_a(f: Callable[..., Any]) -> A: | |
| return A() | |
| @overload | |
| def f_a(arg: int) -> None: ... | |
| @overload | |
| def f_a(arg: str) -> None: ... | |
| @dec_a | |
| def f_a(arg): ... | |
| class B: | |
| def __call__(self, arg: Union[int, str]) -> None: ... | |
| def dec_b(f: Callable[..., Any]) -> B: | |
| return B() | |
| @overload | |
| def f_b(arg: int) -> None: ... | |
| @overload | |
| def f_b(arg: str) -> None: ... | |
| @dec_b | |
| def f_b(arg): ... | |
| class C: | |
| def __call__(self, arg: int) -> None: ... | |
| def dec_c(f: Callable[..., Any]) -> C: | |
| return C() | |
| @overload | |
| def f_c(arg: int) -> None: ... | |
| @overload | |
| def f_c(arg: str) -> None: ... | |
| @dec_c # E: Overloaded function implementation does not accept all possible parameters of signature 2 | |
| def f_c(arg): ... | |
| [builtins fixtures/dict.pyi] | |
| [case testOverloadWithErrorDecorator] | |
| from typing import Any, Callable, TypeVar, overload | |
| def dec_d(f: Callable[..., Any]) -> int: ... | |
| @overload | |
| def f_d(arg: int) -> None: ... | |
| @overload | |
| def f_d(arg: str) -> None: ... | |
| @dec_d # E: "int" not callable | |
| def f_d(arg): ... | |
| Bad1 = TypeVar('Good') # type: ignore | |
| def dec_e(f: Bad1) -> Bad1: ... # type: ignore | |
| @overload | |
| def f_e(arg: int) -> None: ... | |
| @overload | |
| def f_e(arg: str) -> None: ... | |
| @dec_e # E: Bad1? not callable | |
| def f_e(arg): ... | |
| class Bad2: | |
| def __getattr__(self, attr): | |
| # __getattr__ is not called for implicit `__call__` | |
| if attr == "__call__": | |
| return lambda *a, **kw: print(a, kw) | |
| raise AttributeError | |
| @overload | |
| def f_f(arg: int) -> None: ... | |
| @overload | |
| def f_f(arg: str) -> None: ... | |
| @Bad2() # E: "Bad2" not callable | |
| def f_f(arg): ... | |
| [builtins fixtures/dict.pyi] | |
| [case testOverloadIfBasic] | |
| # flags: --always-true True --always-false False | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| # ----- | |
| # Test basic overload merging | |
| # ----- | |
| @overload | |
| def f1(g: A) -> A: ... | |
| if True: | |
| @overload | |
| def f1(g: B) -> B: ... | |
| def f1(g): ... | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f1(B())) # N: Revealed type is "__main__.B" | |
| @overload | |
| def f2(g: A) -> A: ... | |
| @overload | |
| def f2(g: B) -> B: ... | |
| if False: | |
| @overload | |
| def f2(g: C) -> C: ... | |
| def f2(g): ... | |
| reveal_type(f2(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f2(C())) # E: No overload variant of "f2" matches argument type "C" \ | |
| # N: Possible overload variants: \ | |
| # N: def f2(g: A) -> A \ | |
| # N: def f2(g: B) -> B \ | |
| # N: Revealed type is "Any" | |
| @overload | |
| def f3(g: A) -> A: ... | |
| @overload | |
| def f3(g: B) -> B: ... | |
| if maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "maybe_true" is not defined | |
| @overload | |
| def f3(g: C) -> C: ... | |
| def f3(g): ... | |
| reveal_type(f3(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f3(C())) # E: No overload variant of "f3" matches argument type "C" \ | |
| # N: Possible overload variants: \ | |
| # N: def f3(g: A) -> A \ | |
| # N: def f3(g: B) -> B \ | |
| # N: Revealed type is "Any" | |
| if True: | |
| @overload | |
| def f4(g: A) -> A: ... | |
| if True: | |
| @overload | |
| def f4(g: B) -> B: ... | |
| @overload | |
| def f4(g: C) -> C: ... | |
| def f4(g): ... | |
| reveal_type(f4(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f4(B())) # N: Revealed type is "__main__.B" | |
| reveal_type(f4(C())) # N: Revealed type is "__main__.C" | |
| if True: | |
| @overload | |
| def f5(g: A) -> A: ... | |
| @overload | |
| def f5(g: B) -> B: ... | |
| if True: | |
| @overload | |
| def f5(g: C) -> C: ... | |
| @overload | |
| def f5(g: D) -> D: ... | |
| def f5(g): ... | |
| reveal_type(f5(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f5(B())) # N: Revealed type is "__main__.B" | |
| reveal_type(f5(C())) # N: Revealed type is "__main__.C" | |
| reveal_type(f5(D())) # N: Revealed type is "__main__.D" | |
| [case testOverloadIfSysVersion] | |
| # flags: --python-version 3.10 | |
| from typing import overload | |
| import sys | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| # ----- | |
| # "Real" world example | |
| # Test overload merging for sys.version_info | |
| # ----- | |
| @overload | |
| def f1(g: A) -> A: ... | |
| if sys.version_info >= (3, 10): | |
| @overload | |
| def f1(g: B) -> B: ... | |
| def f1(g): ... | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f1(B())) # N: Revealed type is "__main__.B" | |
| @overload | |
| def f2(g: A) -> A: ... | |
| @overload | |
| def f2(g: B) -> B: ... | |
| if sys.version_info >= (3, 11): | |
| @overload | |
| def f2(g: C) -> C: ... | |
| def f2(g): ... | |
| reveal_type(f2(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f2(C())) # E: No overload variant of "f2" matches argument type "C" \ | |
| # N: Possible overload variants: \ | |
| # N: def f2(g: A) -> A \ | |
| # N: def f2(g: B) -> B \ | |
| # N: Revealed type is "Any" | |
| [builtins fixtures/ops.pyi] | |
| [case testOverloadIfMerging] | |
| # flags: --always-true True | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| # ----- | |
| # Test overload merging | |
| # ----- | |
| @overload | |
| def f1(g: A) -> A: ... | |
| if True: | |
| # Some comment | |
| @overload | |
| def f1(g: B) -> B: ... | |
| def f1(g): ... | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f1(B())) # N: Revealed type is "__main__.B" | |
| @overload | |
| def f2(g: A) -> A: ... | |
| if True: | |
| @overload | |
| def f2(g: bytes) -> B: ... | |
| @overload | |
| def f2(g: B) -> C: ... | |
| def f2(g): ... | |
| reveal_type(f2(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f2(B())) # N: Revealed type is "__main__.C" | |
| @overload | |
| def f3(g: A) -> A: ... | |
| @overload | |
| def f3(g: B) -> B: ... | |
| if True: | |
| def f3(g): ... | |
| reveal_type(f3(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f3(B())) # N: Revealed type is "__main__.B" | |
| if True: | |
| @overload | |
| def f4(g: A) -> A: ... | |
| @overload | |
| def f4(g: B) -> B: ... | |
| def f4(g): ... | |
| reveal_type(f4(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f4(B())) # N: Revealed type is "__main__.B" | |
| if True: | |
| # Some comment | |
| @overload | |
| def f5(g: A) -> A: ... | |
| @overload | |
| def f5(g: B) -> B: ... | |
| def f5(g): ... | |
| reveal_type(f5(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f5(B())) # N: Revealed type is "__main__.B" | |
| [case testOverloadIfNotMerging] | |
| # flags: --always-true True | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| # ----- | |
| # Don't merge if IfStmt contains nodes other than overloads | |
| # ----- | |
| @overload # E: An overloaded function outside a stub file must have an implementation | |
| def f1(g: A) -> A: ... | |
| @overload | |
| def f1(g: B) -> B: ... | |
| if True: | |
| @overload # E: Name "f1" already defined on line 12 \ | |
| # E: Single overload definition, multiple required | |
| def f1(g: C) -> C: ... | |
| pass # Some other action | |
| def f1(g): ... # E: Name "f1" already defined on line 12 | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f1(C())) # E: No overload variant of "f1" matches argument type "C" \ | |
| # N: Possible overload variants: \ | |
| # N: def f1(g: A) -> A \ | |
| # N: def f1(g: B) -> B \ | |
| # N: Revealed type is "Any" | |
| if True: | |
| pass # Some other action | |
| @overload # E: Single overload definition, multiple required | |
| def f2(g: A) -> A: ... | |
| @overload # E: Name "f2" already defined on line 26 | |
| def f2(g: B) -> B: ... | |
| @overload | |
| def f2(g: C) -> C: ... | |
| def f2(g): ... | |
| reveal_type(f2(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f2(C())) # N: Revealed type is "__main__.A" \ | |
| # E: Argument 1 to "f2" has incompatible type "C"; expected "A" | |
| [case testOverloadIfOldStyle] | |
| # flags: --always-false var_false --always-true var_true | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| # ----- | |
| # Test old style to make sure it still works | |
| # ----- | |
| var_true = True | |
| var_false = False | |
| if var_false: | |
| @overload | |
| def f1(g: A) -> A: ... | |
| @overload | |
| def f1(g: B) -> B: ... | |
| def f1(g): ... | |
| elif var_true: | |
| @overload | |
| def f1(g: A) -> A: ... | |
| @overload | |
| def f1(g: B) -> B: ... | |
| def f1(g): ... | |
| else: | |
| @overload | |
| def f1(g: A) -> A: ... | |
| @overload | |
| def f1(g: B) -> B: ... | |
| def f1(g): ... | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f1(B())) # N: Revealed type is "__main__.B" | |
| [case testOverloadIfElse] | |
| # flags: --always-true True --always-false False | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| # ----- | |
| # Match the first always-true block | |
| # ----- | |
| @overload | |
| def f1(x: A) -> A: ... | |
| if True: | |
| @overload | |
| def f1(x: B) -> B: ... | |
| elif False: | |
| @overload | |
| def f1(x: C) -> C: ... | |
| else: | |
| @overload | |
| def f1(x: D) -> D: ... | |
| def f1(x): ... | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f1(B())) # N: Revealed type is "__main__.B" | |
| reveal_type(f1(C())) # E: No overload variant of "f1" matches argument type "C" \ | |
| # N: Possible overload variants: \ | |
| # N: def f1(x: A) -> A \ | |
| # N: def f1(x: B) -> B \ | |
| # N: Revealed type is "Any" | |
| @overload | |
| def f2(x: A) -> A: ... | |
| if False: | |
| @overload | |
| def f2(x: B) -> B: ... | |
| elif True: | |
| @overload | |
| def f2(x: C) -> C: ... | |
| else: | |
| @overload | |
| def f2(x: D) -> D: ... | |
| def f2(x): ... | |
| reveal_type(f2(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f2(B())) # E: No overload variant of "f2" matches argument type "B" \ | |
| # N: Possible overload variants: \ | |
| # N: def f2(x: A) -> A \ | |
| # N: def f2(x: C) -> C \ | |
| # N: Revealed type is "Any" | |
| reveal_type(f2(C())) # N: Revealed type is "__main__.C" | |
| @overload | |
| def f3(x: A) -> A: ... | |
| if False: | |
| @overload | |
| def f3(x: B) -> B: ... | |
| elif False: | |
| @overload | |
| def f3(x: C) -> C: ... | |
| else: | |
| @overload | |
| def f3(x: D) -> D: ... | |
| def f3(x): ... | |
| reveal_type(f3(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f3(C())) # E: No overload variant of "f3" matches argument type "C" \ | |
| # N: Possible overload variants: \ | |
| # N: def f3(x: A) -> A \ | |
| # N: def f3(x: D) -> D \ | |
| # N: Revealed type is "Any" | |
| reveal_type(f3(D())) # N: Revealed type is "__main__.D" | |
| [case testOverloadIfElse2] | |
| # flags: --always-true True | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| # ----- | |
| # Match the first always-true block | |
| # Don't merge overloads if can't be certain about execution of block | |
| # ----- | |
| @overload | |
| def f1(x: A) -> A: ... | |
| if True: | |
| @overload | |
| def f1(x: B) -> B: ... | |
| else: | |
| @overload | |
| def f1(x: D) -> D: ... | |
| def f1(x): ... | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f1(B())) # N: Revealed type is "__main__.B" | |
| reveal_type(f1(D())) # E: No overload variant of "f1" matches argument type "D" \ | |
| # N: Possible overload variants: \ | |
| # N: def f1(x: A) -> A \ | |
| # N: def f1(x: B) -> B \ | |
| # N: Revealed type is "Any" | |
| @overload | |
| def f2(x: A) -> A: ... | |
| if True: | |
| @overload | |
| def f2(x: B) -> B: ... | |
| elif maybe_true: | |
| @overload | |
| def f2(x: C) -> C: ... | |
| else: | |
| @overload | |
| def f2(x: D) -> D: ... | |
| def f2(x): ... | |
| reveal_type(f2(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f2(B())) # N: Revealed type is "__main__.B" | |
| reveal_type(f2(C())) # E: No overload variant of "f2" matches argument type "C" \ | |
| # N: Possible overload variants: \ | |
| # N: def f2(x: A) -> A \ | |
| # N: def f2(x: B) -> B \ | |
| # N: Revealed type is "Any" | |
| @overload # E: Single overload definition, multiple required | |
| def f3(x: A) -> A: ... | |
| if maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "maybe_true" is not defined | |
| @overload | |
| def f3(x: B) -> B: ... | |
| elif True: | |
| @overload | |
| def f3(x: C) -> C: ... | |
| else: | |
| @overload | |
| def f3(x: D) -> D: ... | |
| def f3(x): ... | |
| reveal_type(f3(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f3(B())) # E: No overload variant of "f3" matches argument type "B" \ | |
| # N: Possible overload variant: \ | |
| # N: def f3(x: A) -> A \ | |
| # N: Revealed type is "Any" | |
| @overload # E: Single overload definition, multiple required | |
| def f4(x: A) -> A: ... | |
| if maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "maybe_true" is not defined | |
| @overload | |
| def f4(x: B) -> B: ... | |
| else: | |
| @overload | |
| def f4(x: D) -> D: ... | |
| def f4(x): ... | |
| reveal_type(f4(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f4(B())) # E: No overload variant of "f4" matches argument type "B" \ | |
| # N: Possible overload variant: \ | |
| # N: def f4(x: A) -> A \ | |
| # N: Revealed type is "Any" | |
| [case testOverloadIfElse3] | |
| # flags: --always-false False | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| class E: ... | |
| # ----- | |
| # Match the first always-true block | |
| # Don't merge overloads if can't be certain about execution of block | |
| # ----- | |
| @overload | |
| def f1(x: A) -> A: ... | |
| if False: | |
| @overload | |
| def f1(x: B) -> B: ... | |
| else: | |
| @overload | |
| def f1(x: D) -> D: ... | |
| def f1(x): ... | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f1(B())) # E: No overload variant of "f1" matches argument type "B" \ | |
| # N: Possible overload variants: \ | |
| # N: def f1(x: A) -> A \ | |
| # N: def f1(x: D) -> D \ | |
| # N: Revealed type is "Any" | |
| reveal_type(f1(D())) # N: Revealed type is "__main__.D" | |
| @overload # E: Single overload definition, multiple required | |
| def f2(x: A) -> A: ... | |
| if False: | |
| @overload | |
| def f2(x: B) -> B: ... | |
| elif maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "maybe_true" is not defined | |
| @overload | |
| def f2(x: C) -> C: ... | |
| else: | |
| @overload | |
| def f2(x: D) -> D: ... | |
| def f2(x): ... | |
| reveal_type(f2(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f2(C())) # E: No overload variant of "f2" matches argument type "C" \ | |
| # N: Possible overload variant: \ | |
| # N: def f2(x: A) -> A \ | |
| # N: Revealed type is "Any" | |
| @overload # E: Single overload definition, multiple required | |
| def f3(x: A) -> A: ... | |
| if maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "maybe_true" is not defined | |
| @overload | |
| def f3(x: B) -> B: ... | |
| elif False: | |
| @overload | |
| def f3(x: C) -> C: ... | |
| else: | |
| @overload | |
| def f3(x: D) -> D: ... | |
| def f3(x): ... | |
| reveal_type(f3(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f3(B())) # E: No overload variant of "f3" matches argument type "B" \ | |
| # N: Possible overload variant: \ | |
| # N: def f3(x: A) -> A \ | |
| # N: Revealed type is "Any" | |
| def g(bool_var: bool) -> None: | |
| @overload | |
| def f4(x: A) -> A: ... | |
| if bool_var: # E: Condition can't be inferred, unable to merge overloads | |
| @overload | |
| def f4(x: B) -> B: ... | |
| elif maybe_true: # E: Name "maybe_true" is not defined | |
| # No 'Condition cannot be inferred' error here since it's already | |
| # emitted on the first condition, 'bool_var', above. | |
| @overload | |
| def f4(x: C) -> C: ... | |
| else: | |
| @overload | |
| def f4(x: D) -> D: ... | |
| @overload | |
| def f4(x: E) -> E: ... | |
| def f4(x): ... | |
| reveal_type(f4(E())) # N: Revealed type is "__main__.E" | |
| reveal_type(f4(B())) # E: No overload variant of "f4" matches argument type "B" \ | |
| # N: Possible overload variants: \ | |
| # N: def f4(x: A) -> A \ | |
| # N: def f4(x: E) -> E \ | |
| # N: Revealed type is "Any" | |
| [case testOverloadIfSkipUnknownExecution] | |
| # flags: --always-true True | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| # ----- | |
| # If blocks should be skipped if execution can't be certain | |
| # Overload name must match outer name | |
| # ----- | |
| @overload # E: Single overload definition, multiple required | |
| def f1(x: A) -> A: ... | |
| if maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "maybe_true" is not defined | |
| @overload | |
| def f1(x: B) -> B: ... | |
| def f1(x): ... | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| if maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "maybe_true" is not defined | |
| @overload | |
| def f2(x: A) -> A: ... | |
| @overload | |
| def f2(x: B) -> B: ... | |
| @overload | |
| def f2(x: C) -> C: ... | |
| def f2(x): ... | |
| reveal_type(f2(A())) # E: No overload variant of "f2" matches argument type "A" \ | |
| # N: Possible overload variants: \ | |
| # N: def f2(x: B) -> B \ | |
| # N: def f2(x: C) -> C \ | |
| # N: Revealed type is "Any" | |
| if True: | |
| @overload # E: Single overload definition, multiple required | |
| def f3(x: A) -> A: ... | |
| if maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "maybe_true" is not defined | |
| @overload | |
| def f3(x: B) -> B: ... | |
| def f3(x): ... | |
| reveal_type(f3(A())) # N: Revealed type is "__main__.A" | |
| if True: | |
| if maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "maybe_true" is not defined | |
| @overload | |
| def f4(x: A) -> A: ... | |
| @overload | |
| def f4(x: B) -> B: ... | |
| @overload | |
| def f4(x: C) -> C: ... | |
| def f4(x): ... | |
| reveal_type(f4(A())) # E: No overload variant of "f4" matches argument type "A" \ | |
| # N: Possible overload variants: \ | |
| # N: def f4(x: B) -> B \ | |
| # N: def f4(x: C) -> C \ | |
| # N: Revealed type is "Any" | |
| [case testOverloadIfDontSkipUnrelatedOverload] | |
| # flags: --always-true True | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| # ----- | |
| # Don't skip if block if overload name doesn't match outer name | |
| # ----- | |
| @overload # E: Single overload definition, multiple required | |
| def f1(x: A) -> A: ... | |
| if maybe_true: # E: Name "maybe_true" is not defined | |
| @overload # E: Single overload definition, multiple required | |
| def g1(x: B) -> B: ... | |
| def f1(x): ... # E: Name "f1" already defined on line 13 | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| if maybe_true: # E: Name "maybe_true" is not defined | |
| @overload # E: Single overload definition, multiple required | |
| def g2(x: A) -> A: ... | |
| @overload | |
| def f2(x: B) -> B: ... | |
| @overload | |
| def f2(x: C) -> C: ... | |
| def f2(x): ... | |
| reveal_type(f2(A())) # E: No overload variant of "f2" matches argument type "A" \ | |
| # N: Possible overload variants: \ | |
| # N: def f2(x: B) -> B \ | |
| # N: def f2(x: C) -> C \ | |
| # N: Revealed type is "Any" | |
| if True: | |
| @overload # E: Single overload definition, multiple required | |
| def f3(x: A) -> A: ... | |
| def f3(x): ... | |
| if maybe_true: # E: Name "maybe_true" is not defined | |
| @overload # E: Single overload definition, multiple required | |
| def g3(x: B) -> B: ... | |
| reveal_type(f3(A())) # N: Revealed type is "__main__.A" | |
| if True: | |
| if maybe_true: # E: Name "maybe_true" is not defined | |
| @overload # E: Single overload definition, multiple required | |
| def g4(x: A) -> A: ... | |
| @overload | |
| def f4(x: B) -> B: ... | |
| @overload | |
| def f4(x: C) -> C: ... | |
| def f4(x): ... | |
| reveal_type(f4(A())) # E: No overload variant of "f4" matches argument type "A" \ | |
| # N: Possible overload variants: \ | |
| # N: def f4(x: B) -> B \ | |
| # N: def f4(x: C) -> C \ | |
| # N: Revealed type is "Any" | |
| [case testOverloadIfNotMergingDifferentNames] | |
| # flags: --always-true True | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| # ----- | |
| # Don't merge overloads if IfStmts contains overload with different name | |
| # ----- | |
| @overload # E: An overloaded function outside a stub file must have an implementation | |
| def f1(x: A) -> A: ... | |
| @overload | |
| def f1(x: B) -> B: ... | |
| if True: | |
| @overload # E: Single overload definition, multiple required | |
| def g1(x: C) -> C: ... | |
| def f1(x): ... # E: Name "f1" already defined on line 13 | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f1(C())) # E: No overload variant of "f1" matches argument type "C" \ | |
| # N: Possible overload variants: \ | |
| # N: def f1(x: A) -> A \ | |
| # N: def f1(x: B) -> B \ | |
| # N: Revealed type is "Any" | |
| if True: | |
| @overload # E: Single overload definition, multiple required | |
| def g2(x: A) -> A: ... | |
| @overload | |
| def f2(x: B) -> B: ... | |
| @overload | |
| def f2(x: C) -> C: ... | |
| def f2(x): ... | |
| reveal_type(f2(A())) # E: No overload variant of "f2" matches argument type "A" \ | |
| # N: Possible overload variants: \ | |
| # N: def f2(x: B) -> B \ | |
| # N: def f2(x: C) -> C \ | |
| # N: Revealed type is "Any" | |
| reveal_type(f2(B())) # N: Revealed type is "__main__.B" | |
| if True: | |
| if True: | |
| @overload # E: Single overload definition, multiple required | |
| def g3(x: A) -> A: ... | |
| @overload | |
| def f3(x: B) -> B: ... | |
| @overload | |
| def f3(x: C) -> C: ... | |
| def f3(x): ... | |
| reveal_type(f3(A())) # E: No overload variant of "f3" matches argument type "A" \ | |
| # N: Possible overload variants: \ | |
| # N: def f3(x: B) -> B \ | |
| # N: def f3(x: C) -> C \ | |
| # N: Revealed type is "Any" | |
| reveal_type(f3(B())) # N: Revealed type is "__main__.B" | |
| [case testOverloadIfSplitFunctionDef] | |
| # flags: --always-true True --always-false False | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| # ----- | |
| # Test split FuncDefs | |
| # ----- | |
| @overload | |
| def f1(x: A) -> A: ... | |
| @overload | |
| def f1(x: B) -> B: ... | |
| if True: | |
| def f1(x): ... | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| @overload | |
| def f2(x: A) -> A: ... | |
| @overload | |
| def f2(x: B) -> B: ... | |
| if False: | |
| def f2(x): ... | |
| else: | |
| def f2(x): ... | |
| reveal_type(f2(A())) # N: Revealed type is "__main__.A" | |
| @overload | |
| def f3(x: A) -> A: ... | |
| @overload | |
| def f3(x: B) -> B: ... | |
| if True: | |
| def f3(x): ... | |
| else: | |
| pass # some other node (OK, because statically unreachable) | |
| def f3(x): ... | |
| reveal_type(f3(A())) # N: Revealed type is "__main__.A" | |
| [case testOverloadIfMixed] | |
| # flags: --always-true True --always-false False | |
| from typing import overload, TYPE_CHECKING | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| if maybe_var: # E: Name "maybe_var" is not defined | |
| pass | |
| if True: | |
| @overload | |
| def f1(x: A) -> A: ... | |
| @overload | |
| def f1(x: B) -> B: ... | |
| def f1(x): ... | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f1(B())) # N: Revealed type is "__main__.B" | |
| if True: | |
| @overload | |
| def f2(x: A) -> A: ... | |
| @overload | |
| def f2(x: B) -> B: ... | |
| def f2(x): ... | |
| reveal_type(f2(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f2(B())) # N: Revealed type is "__main__.B" | |
| if True: | |
| @overload | |
| def f3(x: A) -> A: ... | |
| @overload | |
| def f3(x: B) -> B: ... | |
| def f3(x): ... | |
| reveal_type(f3(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f3(B())) # N: Revealed type is "__main__.B" | |
| # Don't crash with AssignmentStmt if elif | |
| @overload # E: Single overload definition, multiple required | |
| def f4(x: A) -> A: ... | |
| if False: | |
| @overload | |
| def f4(x: B) -> B: ... | |
| elif True: | |
| var = 1 | |
| def f4(x): ... # E: Name "f4" already defined on line 39 | |
| if TYPE_CHECKING: | |
| @overload | |
| def f5(x: A) -> A: ... | |
| @overload | |
| def f5(x: B) -> B: ... | |
| def f5(x): ... | |
| reveal_type(f5(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f5(B())) # N: Revealed type is "__main__.B" | |
| # Test from check-functions - testUnconditionalRedefinitionOfConditionalFunction | |
| # Don't merge If blocks if they appear before any overloads | |
| # and don't contain any overloads themselves. | |
| if maybe_true: # E: Name "maybe_true" is not defined | |
| def f6(x): ... | |
| def f6(x): ... # E: Name "f6" already defined on line 61 | |
| if maybe_true: # E: Name "maybe_true" is not defined | |
| pass # Some other node | |
| def f7(x): ... | |
| def f7(x): ... # E: Name "f7" already defined on line 66 | |
| @overload | |
| def f8(x: A) -> A: ... | |
| @overload | |
| def f8(x: B) -> B: ... | |
| if False: | |
| def f8(x: C) -> C: ... | |
| def f8(x): ... | |
| reveal_type(f8(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f8(C())) # E: No overload variant of "f8" matches argument type "C" \ | |
| # N: Possible overload variants: \ | |
| # N: def f8(x: A) -> A \ | |
| # N: def f8(x: B) -> B \ | |
| # N: Revealed type is "Any" | |
| if maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "maybe_true" is not defined | |
| @overload | |
| def f9(x: A) -> A: ... | |
| if another_maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "another_maybe_true" is not defined | |
| @overload | |
| def f9(x: B) -> B: ... | |
| @overload | |
| def f9(x: C) -> C: ... | |
| @overload | |
| def f9(x: D) -> D: ... | |
| def f9(x): ... | |
| reveal_type(f9(A())) # E: No overload variant of "f9" matches argument type "A" \ | |
| # N: Possible overload variants: \ | |
| # N: def f9(x: C) -> C \ | |
| # N: def f9(x: D) -> D \ | |
| # N: Revealed type is "Any" | |
| reveal_type(f9(C())) # N: Revealed type is "__main__.C" | |
| if True: | |
| if maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "maybe_true" is not defined | |
| @overload | |
| def f10(x: A) -> A: ... | |
| if another_maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "another_maybe_true" is not defined | |
| @overload | |
| def f10(x: B) -> B: ... | |
| @overload | |
| def f10(x: C) -> C: ... | |
| @overload | |
| def f10(x: D) -> D: ... | |
| def f10(x): ... | |
| reveal_type(f10(A())) # E: No overload variant of "f10" matches argument type "A" \ | |
| # N: Possible overload variants: \ | |
| # N: def f10(x: C) -> C \ | |
| # N: def f10(x: D) -> D \ | |
| # N: Revealed type is "Any" | |
| reveal_type(f10(C())) # N: Revealed type is "__main__.C" | |
| if some_var: # E: Name "some_var" is not defined | |
| pass | |
| @overload | |
| def f11(x: A) -> A: ... | |
| @overload | |
| def f11(x: B) -> B: ... | |
| def f11(x): ... | |
| reveal_type(f11(A())) # N: Revealed type is "__main__.A" | |
| if True: | |
| if some_var: # E: Name "some_var" is not defined | |
| pass | |
| @overload | |
| def f12(x: A) -> A: ... | |
| @overload | |
| def f12(x: B) -> B: ... | |
| def f12(x): ... | |
| reveal_type(f12(A())) # N: Revealed type is "__main__.A" | |
| [typing fixtures/typing-medium.pyi] | |
| [case testAdjacentConditionalOverloads] | |
| # flags: --always-true true_alias | |
| from typing import overload | |
| true_alias = True | |
| if true_alias: | |
| @overload | |
| def ham(v: str) -> list[str]: ... | |
| @overload | |
| def ham(v: int) -> list[int]: ... | |
| def ham(v: "int | str") -> "list[str] | list[int]": | |
| return [] | |
| if true_alias: | |
| @overload | |
| def spam(v: str) -> str: ... | |
| @overload | |
| def spam(v: int) -> int: ... | |
| def spam(v: "int | str") -> "str | int": | |
| return "" | |
| reveal_type(ham) # N: Revealed type is "Overload(def (v: builtins.str) -> builtins.list[builtins.str], def (v: builtins.int) -> builtins.list[builtins.int])" | |
| reveal_type(spam) # N: Revealed type is "Overload(def (v: builtins.str) -> builtins.str, def (v: builtins.int) -> builtins.int)" | |
| reveal_type(ham("")) # N: Revealed type is "builtins.list[builtins.str]" | |
| reveal_type(ham(0)) # N: Revealed type is "builtins.list[builtins.int]" | |
| reveal_type(spam("")) # N: Revealed type is "builtins.str" | |
| reveal_type(spam(0)) # N: Revealed type is "builtins.int" | |
| [case testOverloadIfUnconditionalFuncDef] | |
| # flags: --always-true True --always-false False | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| # ----- | |
| # Don't merge conditional FuncDef after unconditional one | |
| # ----- | |
| @overload | |
| def f1(x: A) -> A: ... | |
| @overload | |
| def f1(x: B) -> B: ... | |
| def f1(x): ... | |
| @overload | |
| def f2(x: A) -> A: ... | |
| if True: | |
| @overload | |
| def f2(x: B) -> B: ... | |
| def f2(x): ... | |
| if True: | |
| def f2(x): ... # E: Name "f2" already defined on line 17 | |
| [case testOverloadItemHasMoreGeneralReturnType] | |
| from typing import overload | |
| @overload | |
| def f() -> object: ... | |
| @overload | |
| def f(x: int) -> object: ... | |
| def f(x: int = 0) -> int: | |
| return x | |
| @overload | |
| def g() -> object: ... | |
| @overload | |
| def g(x: int) -> str: ... | |
| def g(x: int = 0) -> int: # E: Overloaded function implementation cannot produce return type of signature 2 | |
| return x | |
| [case testOverloadIfNestedOk] | |
| # flags: --always-true True --always-false False | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| @overload | |
| def f1(g: A) -> A: ... | |
| if True: | |
| @overload | |
| def f1(g: B) -> B: ... | |
| if True: | |
| @overload | |
| def f1(g: C) -> C: ... | |
| @overload | |
| def f1(g: D) -> D: ... | |
| def f1(g): ... | |
| reveal_type(f1(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f1(B())) # N: Revealed type is "__main__.B" | |
| reveal_type(f1(C())) # N: Revealed type is "__main__.C" | |
| reveal_type(f1(D())) # N: Revealed type is "__main__.D" | |
| @overload | |
| def f2(g: A) -> A: ... | |
| if True: | |
| @overload | |
| def f2(g: B) -> B: ... | |
| if True: | |
| @overload | |
| def f2(g: C) -> C: ... | |
| if True: | |
| @overload | |
| def f2(g: D) -> D: ... | |
| def f2(g): ... | |
| reveal_type(f2(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f2(B())) # N: Revealed type is "__main__.B" | |
| reveal_type(f2(C())) # N: Revealed type is "__main__.C" | |
| reveal_type(f2(D())) # N: Revealed type is "__main__.D" | |
| @overload | |
| def f3(g: A) -> A: ... | |
| if True: | |
| if True: | |
| @overload | |
| def f3(g: B) -> B: ... | |
| if True: | |
| @overload | |
| def f3(g: C) -> C: ... | |
| def f3(g): ... | |
| reveal_type(f3(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f3(B())) # N: Revealed type is "__main__.B" | |
| reveal_type(f3(C())) # N: Revealed type is "__main__.C" | |
| @overload | |
| def f4(g: A) -> A: ... | |
| if True: | |
| if False: | |
| @overload | |
| def f4(g: B) -> B: ... | |
| else: | |
| @overload | |
| def f4(g: C) -> C: ... | |
| def f4(g): ... | |
| reveal_type(f4(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f4(B())) # E: No overload variant of "f4" matches argument type "B" \ | |
| # N: Possible overload variants: \ | |
| # N: def f4(g: A) -> A \ | |
| # N: def f4(g: C) -> C \ | |
| # N: Revealed type is "Any" | |
| reveal_type(f4(C())) # N: Revealed type is "__main__.C" | |
| @overload | |
| def f5(g: A) -> A: ... | |
| if True: | |
| if False: | |
| @overload | |
| def f5(g: B) -> B: ... | |
| elif True: | |
| @overload | |
| def f5(g: C) -> C: ... | |
| def f5(g): ... | |
| reveal_type(f5(A())) # N: Revealed type is "__main__.A" | |
| reveal_type(f5(B())) # E: No overload variant of "f5" matches argument type "B" \ | |
| # N: Possible overload variants: \ | |
| # N: def f5(g: A) -> A \ | |
| # N: def f5(g: C) -> C \ | |
| # N: Revealed type is "Any" | |
| reveal_type(f5(C())) # N: Revealed type is "__main__.C" | |
| [case testOverloadIfNestedFailure] | |
| # flags: --always-true True --always-false False | |
| from typing import overload | |
| class A: ... | |
| class B: ... | |
| class C: ... | |
| class D: ... | |
| @overload # E: Single overload definition, multiple required | |
| def f1(g: A) -> A: ... | |
| if True: | |
| @overload # E: Single overload definition, multiple required | |
| def f1(g: B) -> B: ... # E: Incompatible redefinition (redefinition with type "Callable[[B], B]", original type "Callable[[A], A]") | |
| if maybe_true: # E: Condition can't be inferred, unable to merge overloads \ | |
| # E: Name "maybe_true" is not defined | |
| @overload | |
| def f1(g: C) -> C: ... | |
| @overload | |
| def f1(g: D) -> D: ... | |
| def f1(g): ... # E: Name "f1" already defined on line 9 | |
| @overload # E: Single overload definition, multiple required | |
| def f2(g: A) -> A: ... | |
| if True: | |
| if False: | |
| @overload | |
| def f2(g: B) -> B: ... | |
| elif maybe_true: # E: Name "maybe_true" is not defined | |
| @overload # E: Single overload definition, multiple required | |
| def f2(g: C) -> C: ... # E: Incompatible redefinition (redefinition with type "Callable[[C], C]", original type "Callable[[A], A]") | |
| def f2(g): ... # E: Name "f2" already defined on line 21 | |
| @overload # E: Single overload definition, multiple required | |
| def f3(g: A) -> A: ... | |
| if True: | |
| @overload # E: Single overload definition, multiple required | |
| def f3(g: B) -> B: ... # E: Incompatible redefinition (redefinition with type "Callable[[B], B]", original type "Callable[[A], A]") | |
| if True: | |
| pass # Some other node | |
| @overload # E: Name "f3" already defined on line 32 \ | |
| # E: An overloaded function outside a stub file must have an implementation | |
| def f3(g: C) -> C: ... | |
| @overload | |
| def f3(g: D) -> D: ... | |
| def f3(g): ... # E: Name "f3" already defined on line 32 | |
| [case testOverloadingWithParamSpec] | |
| from typing import TypeVar, Callable, Any, overload | |
| from typing_extensions import ParamSpec, Concatenate | |
| P = ParamSpec("P") | |
| R = TypeVar("R") | |
| @overload | |
| def func(x: Callable[Concatenate[Any, P], R]) -> Callable[P, R]: ... | |
| @overload | |
| def func(x: Callable[P, R]) -> Callable[Concatenate[str, P], R]: ... | |
| def func(x: Callable[..., R]) -> Callable[..., R]: ... | |
| def foo(arg1: str, arg2: int) -> bytes: ... | |
| reveal_type(func(foo)) # N: Revealed type is "def (arg2: builtins.int) -> builtins.bytes" | |
| def bar() -> int: ... | |
| reveal_type(func(bar)) # N: Revealed type is "def (builtins.str) -> builtins.int" | |
| baz: Callable[[str, str], str] = lambda x, y: 'baz' | |
| reveal_type(func(baz)) # N: Revealed type is "def (builtins.str) -> builtins.str" | |
| eggs = lambda: 'eggs' | |
| reveal_type(func(eggs)) # N: Revealed type is "def (builtins.str) -> builtins.str" | |
| spam: Callable[..., str] = lambda x, y: 'baz' | |
| reveal_type(func(spam)) # N: Revealed type is "def (*Any, **Any) -> Any" | |
| [builtins fixtures/paramspec.pyi] | |
| [case testGenericOverloadOverlapWithType] | |
| import m | |
| [file m.pyi] | |
| from typing import TypeVar, Type, overload, Callable | |
| T = TypeVar("T", bound=str) | |
| @overload | |
| def foo(x: Type[T] | int) -> int: ... | |
| @overload | |
| def foo(x: Callable[[int], bool]) -> str: ... | |
| [case testGenericOverloadOverlapWithCollection] | |
| import m | |
| [file m.pyi] | |
| from typing import TypeVar, Sequence, overload, List | |
| T = TypeVar("T", bound=str) | |
| @overload | |
| def foo(x: List[T]) -> str: ... | |
| @overload | |
| def foo(x: Sequence[int]) -> int: ... | |
| [builtins fixtures/list.pyi] | |
| # Also see `check-python38.test` for similar tests with `/` args: | |
| [case testOverloadPositionalOnlyErrorMessageOldStyle] | |
| from typing import overload | |
| @overload | |
| def foo(__a: int): ... | |
| @overload | |
| def foo(a: str): ... | |
| def foo(a): ... | |
| foo(a=1) | |
| [out] | |
| main:9: error: No overload variant of "foo" matches argument type "int" | |
| main:9: note: Possible overload variants: | |
| main:9: note: def foo(int, /) -> Any | |
| main:9: note: def foo(a: str) -> Any | |
| [case testOverloadUnionGenericBounds] | |
| from typing import overload, TypeVar, Sequence, Union | |
| class Entity: ... | |
| class Assoc: ... | |
| E = TypeVar("E", bound=Entity) | |
| A = TypeVar("A", bound=Assoc) | |
| class Test: | |
| @overload | |
| def foo(self, arg: Sequence[E]) -> None: ... | |
| @overload | |
| def foo(self, arg: Sequence[A]) -> None: ... | |
| def foo(self, arg: Union[Sequence[E], Sequence[A]]) -> None: | |
| ... | |
| [case testOverloadedStaticMethodOnInstance] | |
| from typing import overload | |
| class Snafu(object): | |
| @overload | |
| @staticmethod | |
| def snafu(value: bytes) -> bytes: ... | |
| @overload | |
| @staticmethod | |
| def snafu(value: str) -> str: ... | |
| @staticmethod | |
| def snafu(value): | |
| ... | |
| reveal_type(Snafu().snafu('123')) # N: Revealed type is "builtins.str" | |
| reveal_type(Snafu.snafu('123')) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/staticmethod.pyi] | |
| [case testOverloadedWithInternalTypeVars] | |
| import m | |
| [file m.pyi] | |
| from typing import Callable, TypeVar, overload | |
| T = TypeVar("T") | |
| S = TypeVar("S", bound=str) | |
| @overload | |
| def foo(x: int = ...) -> Callable[[T], T]: ... | |
| @overload | |
| def foo(x: S = ...) -> Callable[[T], T]: ... | |
| [case testOverloadGenericStarArgOverlap] | |
| from typing import Any, Callable, TypeVar, overload, Union, Tuple, List | |
| F = TypeVar("F", bound=Callable[..., Any]) | |
| S = TypeVar("S", bound=int) | |
| def id(f: F) -> F: ... | |
| @overload | |
| def struct(*cols: S) -> int: ... | |
| @overload | |
| def struct(__cols: Union[List[S], Tuple[S, ...]]) -> int: ... | |
| @id | |
| def struct(*cols: Union[S, Union[List[S], Tuple[S, ...]]]) -> int: | |
| pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testRegularGenericDecoratorOverload] | |
| from typing import Callable, overload, TypeVar, List | |
| S = TypeVar("S") | |
| T = TypeVar("T") | |
| def transform(func: Callable[[S], List[T]]) -> Callable[[S], T]: ... | |
| @overload | |
| def foo(x: int) -> List[float]: ... | |
| @overload | |
| def foo(x: str) -> List[str]: ... | |
| def foo(x): ... | |
| reveal_type(transform(foo)) # N: Revealed type is "Overload(def (builtins.int) -> builtins.float, def (builtins.str) -> builtins.str)" | |
| @transform | |
| @overload | |
| def bar(x: int) -> List[float]: ... | |
| @transform | |
| @overload | |
| def bar(x: str) -> List[str]: ... | |
| @transform | |
| def bar(x): ... | |
| reveal_type(bar) # N: Revealed type is "Overload(def (builtins.int) -> builtins.float, def (builtins.str) -> builtins.str)" | |
| [builtins fixtures/paramspec.pyi] | |
| [case testOverloadOverlapWithNameOnlyArgs] | |
| from typing import overload | |
| @overload | |
| def d(x: int) -> int: ... | |
| @overload | |
| def d(f: int, *, x: int) -> str: ... | |
| def d(*args, **kwargs): ... | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadCallableGenericSelf] | |
| from typing import Any, TypeVar, Generic, overload, reveal_type | |
| T = TypeVar("T") | |
| class MyCallable(Generic[T]): | |
| def __init__(self, t: T): | |
| self.t = t | |
| @overload | |
| def __call__(self: "MyCallable[int]") -> str: ... | |
| @overload | |
| def __call__(self: "MyCallable[str]") -> int: ... | |
| def __call__(self): ... | |
| c = MyCallable(5) | |
| reveal_type(c) # N: Revealed type is "__main__.MyCallable[builtins.int]" | |
| reveal_type(c()) # N: Revealed type is "builtins.str" | |
| c2 = MyCallable("test") | |
| reveal_type(c2) # N: Revealed type is "__main__.MyCallable[builtins.str]" | |
| reveal_type(c2()) # should be int # N: Revealed type is "builtins.int" | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadWithStarAnyFallback] | |
| from typing import overload, Any | |
| class A: | |
| @overload | |
| def f(self, e: str) -> str: ... | |
| @overload | |
| def f(self, *args: Any, **kwargs: Any) -> Any: ... | |
| def f(self, *args, **kwargs): | |
| pass | |
| class B: | |
| @overload | |
| def f(self, e: str, **kwargs: Any) -> str: ... | |
| @overload | |
| def f(self, *args: Any, **kwargs: Any) -> Any: ... | |
| def f(self, *args, **kwargs): | |
| pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testOverloadsSafeOverlapAllowed] | |
| from lib import * | |
| [file lib.pyi] | |
| from typing import overload | |
| @overload | |
| def bar(x: object) -> object: ... | |
| @overload | |
| def bar(x: int = ...) -> int: ... | |
| [case testOverloadsInvariantOverlapAllowed] | |
| from lib import * | |
| [file lib.pyi] | |
| from typing import overload, List | |
| @overload | |
| def bar(x: List[int]) -> List[int]: ... | |
| @overload | |
| def bar(x: List[object]) -> List[object]: ... | |
| [case testOverloadsNoneAnyOverlapAllowed] | |
| from lib import * | |
| [file lib.pyi] | |
| from typing import overload, Any | |
| @overload | |
| def foo(x: None) -> int: ... | |
| @overload | |
| def foo(x: object) -> str: ... | |
| @overload | |
| def bar(x: int) -> int: ... | |
| @overload | |
| def bar(x: Any) -> str: ... | |
| [case testOverloadOnInvalidTypeArgument] | |
| from typing import TypeVar, Self, Generic, overload | |
| class C: pass | |
| T = TypeVar("T", bound=C) | |
| class D(Generic[T]): | |
| @overload | |
| def f(self, x: int) -> int: ... | |
| @overload | |
| def f(self, x: str) -> str: ... | |
| def f(Self, x): ... | |
| a: D[str] # E: Type argument "str" of "D" must be a subtype of "C" | |
| reveal_type(a.f(1)) # N: Revealed type is "builtins.int" | |
| reveal_type(a.f("x")) # N: Revealed type is "builtins.str" | |
| [case testMultiAssignFromUnionInOverloadCached] | |
| from typing import Iterable, overload, Union, Optional | |
| @overload | |
| def always_bytes(str_or_bytes: None) -> None: ... | |
| @overload | |
| def always_bytes(str_or_bytes: Union[str, bytes]) -> bytes: ... | |
| def always_bytes(str_or_bytes: Union[None, str, bytes]) -> Optional[bytes]: | |
| pass | |
| class Headers: | |
| def __init__(self, iter: Iterable[tuple[bytes, bytes]]) -> None: ... | |
| headers: Union[Headers, dict[Union[str, bytes], Union[str, bytes]], Iterable[tuple[bytes, bytes]]] | |
| if isinstance(headers, dict): | |
| headers = Headers( | |
| (always_bytes(k), always_bytes(v)) for k, v in headers.items() | |
| ) | |
| reveal_type(headers) # N: Revealed type is "__main__.Headers | typing.Iterable[tuple[builtins.bytes, builtins.bytes]]" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testOverloadUnionCallableSubtype] | |
| from typing import Callable, Union, overload | |
| def f(fn: Callable[[Union[int, str]], Union[int, str]]) -> None: pass | |
| def f1(fn: Callable[[Union[int, str, bytes]], Union[int, str]]) -> None: pass | |
| def f2(fn: Callable[[Union[int, str]], int]) -> None: pass | |
| @overload | |
| def g(x: int) -> int: ... | |
| @overload | |
| def g(x: str) -> str: ... | |
| def g(x): ... | |
| f(g) | |
| f1(g) # E: Argument 1 to "f1" has incompatible type overloaded function; expected "Callable[[int | str | bytes], int | str]" | |
| f2(g) # E: Argument 1 to "f2" has incompatible type overloaded function; expected "Callable[[int | str], int]" | |
| [case testOverloadOverridesUnionCallable] | |
| from typing import overload, Union | |
| class A: | |
| def f(self, x: Union[int, str]) -> None: ... | |
| class B(A): | |
| @overload | |
| def f(self, x: int) -> None: ... | |
| @overload | |
| def f(self, x: str) -> None: ... | |
| def f(self, x: Union[int, str]) -> None: ... | |
| [case testOverloadOverridesUnionCallableGeneric] | |
| from typing import overload, Optional, TypeVar | |
| T = TypeVar("T") | |
| class A: | |
| def f(self, x: Optional[T]) -> Optional[T]: ... | |
| class B(A): | |
| @overload | |
| def f(self, x: None) -> None: ... | |
| @overload | |
| def f(self, x: T) -> T: ... | |
| def f(self, x: Optional[T]) -> Optional[T]: ... | |
| [case testOverloadSubtypingRespectPosArgNames] | |
| from typing import Protocol, overload, Union | |
| class P(Protocol): | |
| def __call__(self, __x: Union[int, str]) -> Union[int, str]: ... | |
| class PBad(Protocol): | |
| def __call__(self, x: Union[int, str]) -> Union[int, str]: ... | |
| @overload | |
| def f(x: int) -> int: ... | |
| @overload | |
| def f(y: str) -> str: ... | |
| def f(*args, **kwargs): | |
| pass | |
| p: P = f | |
| pb: PBad = f # E: Incompatible types in assignment (expression has type overloaded function, variable has type "PBad") \ | |
| # N: "PBad.__call__" has type "def __call__(self, x: int | str) -> int | str" | |
| class A: | |
| def f(self, x: Union[int, str]) -> None: ... | |
| class B(A): | |
| @overload | |
| def f(self, x: int) -> None: ... | |
| @overload | |
| def f(self, y: str) -> None: ... # This is currently allowed (note different name) | |
| def f(self, *args, **kwargs) -> None: ... | |
| [builtins fixtures/tuple.pyi] |