| -- Test cases for the type checker related to subtyping and inheritance with | |
| -- generics. | |
| -- Subtyping + inheritance | |
| -- ----------------------- | |
| [case testSubtypingAndInheritingNonGenericTypeFromGenericType] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| ac: A[C] | |
| ad: A[D] | |
| b: B | |
| if int(): | |
| b = ad # E: Incompatible types in assignment (expression has type "A[D]", variable has type "B") | |
| ad = b # E: Incompatible types in assignment (expression has type "B", variable has type "A[D]") | |
| if int(): | |
| b = ac # E: Incompatible types in assignment (expression has type "A[C]", variable has type "B") | |
| if int(): | |
| b = b | |
| ac = b | |
| class C: pass | |
| class A(Generic[T]): pass | |
| class B(A[C]): pass | |
| class D: pass | |
| [case testSubtypingAndInheritingGenericTypeFromNonGenericType] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| a: A | |
| bc: B[C] | |
| bd: B[D] | |
| if int(): | |
| bc = bd # E: Incompatible types in assignment (expression has type "B[D]", variable has type "B[C]") | |
| bd = bc # E: Incompatible types in assignment (expression has type "B[C]", variable has type "B[D]") | |
| if int(): | |
| bc = a # E: Incompatible types in assignment (expression has type "A", variable has type "B[C]") | |
| bd = a # E: Incompatible types in assignment (expression has type "A", variable has type "B[D]") | |
| if int(): | |
| a = bc | |
| if int(): | |
| a = bd | |
| class A: pass | |
| class B(A, Generic[T]): pass | |
| class C: pass | |
| class D: pass | |
| [case testSubtypingAndInheritingGenericTypeFromGenericType] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| ac: A[C] | |
| ad: A[D] | |
| bcc: B[C, C] | |
| bdc: B[D, C] | |
| if int(): | |
| ad = bcc # E: Incompatible types in assignment (expression has type "B[C, C]", variable has type "A[D]") | |
| if int(): | |
| ad = bdc # E: Incompatible types in assignment (expression has type "B[D, C]", variable has type "A[D]") | |
| bcc = ac # E: Incompatible types in assignment (expression has type "A[C]", variable has type "B[C, C]") | |
| bdc = ac # E: Incompatible types in assignment (expression has type "A[C]", variable has type "B[D, C]") | |
| if int(): | |
| bcc = bcc | |
| bdc = bdc | |
| ac = bcc | |
| if int(): | |
| ac = bdc | |
| class A(Generic[T]): pass | |
| class B(A[S], Generic[T, S]): pass | |
| class C: pass | |
| class D: pass | |
| [case testSubtypingAndInheritingGenericTypeFromGenericTypeAcrossHierarchy] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| X = TypeVar('X') | |
| Y = TypeVar('Y') | |
| ae: A[A[E]] | |
| af: A[A[F]] | |
| cef: C[E, F] | |
| cff: C[F, F] | |
| cfe: C[F, E] | |
| if int(): | |
| ae = cef # E: Incompatible types in assignment (expression has type "C[E, F]", variable has type "A[A[E]]") | |
| af = cfe # E: Incompatible types in assignment (expression has type "C[F, E]", variable has type "A[A[F]]") | |
| if int(): | |
| ae = cfe | |
| af = cef | |
| if int(): | |
| af = cff | |
| class A(Generic[T]): pass | |
| class B(A[S], Generic[T, S]): pass | |
| class C(B[A[X], A[Y]], Generic[X, Y]): pass | |
| class E: pass | |
| class F: pass | |
| [case testIncludingBaseClassTwice] | |
| from typing import TypeVar, Generic | |
| t = TypeVar('t') | |
| class I(Generic[t]): pass | |
| class A(I[C], I[object]): pass # E: Duplicate base class "I" | |
| class C: pass | |
| -- Accessing inherited generic members | |
| -- ----------------------------------- | |
| [case testAccessingMethodInheritedFromGenericType] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| b: B[C, D] | |
| c: C | |
| d: D | |
| b.f(c) # E: Argument 1 to "f" of "A" has incompatible type "C"; expected "D" | |
| b.f(d) | |
| class A(Generic[T]): | |
| def f(self, a: T) -> None: | |
| pass | |
| class B(A[S], Generic[T, S]): pass | |
| class C: pass | |
| class D: pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testAccessingMethodInheritedFromGenericTypeInNonGenericType] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| b: B | |
| c: C | |
| d: D | |
| b.f(c) # E: Argument 1 to "f" of "A" has incompatible type "C"; expected "D" | |
| b.f(d) | |
| class C: pass | |
| class D: pass | |
| class A(Generic[T]): | |
| def f(self, a: T) -> None: | |
| pass | |
| class B(A[D]): pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testAccessingMemberVarInheritedFromGenericType] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| class A(Generic[T]): | |
| def __init__(self, a: T) -> None: | |
| self.a = a | |
| b: B[C, D] | |
| c: C | |
| d: D | |
| b.a = c # E: Incompatible types in assignment (expression has type "C", variable has type "D") | |
| b.a = d | |
| class B(A[S], Generic[T, S]): pass | |
| class C: pass | |
| class D: pass | |
| [builtins fixtures/tuple.pyi] | |
| -- Overriding with generic types | |
| -- ----------------------------- | |
| [case testOverridingMethodInSimpleTypeInheritingGenericType] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| class B(Generic[T]): | |
| def f(self, a: T) -> None: pass | |
| def g(self, a: T) -> None: pass | |
| class C: pass | |
| class D: pass | |
| class A(B[C]): | |
| def f(self, a: D) -> None: pass \ | |
| # E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "C" \ | |
| # N: This violates the Liskov substitution principle \ | |
| # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides | |
| def g(self, a: C) -> None: pass | |
| [out] | |
| [case testOverridingMethodInGenericTypeInheritingSimpleType] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| class C: pass | |
| class B: | |
| def f(self, a: C) -> None: pass | |
| def g(self, a: C) -> None: pass | |
| class A(B, Generic[T]): | |
| def f(self, a: T) -> None: pass \ | |
| # E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "C" \ | |
| # N: This violates the Liskov substitution principle \ | |
| # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides | |
| def g(self, a: 'C') -> None: pass | |
| [out] | |
| [case testOverridingMethodInGenericTypeInheritingGenericType] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| class B(Generic[T]): | |
| def f(self, a: T) -> None: pass | |
| def g(self, a: T) -> None: pass | |
| class A(B[S], Generic[T, S]): | |
| def f(self, a: T) -> None: pass \ | |
| # E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "S" \ | |
| # N: This violates the Liskov substitution principle \ | |
| # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides | |
| def g(self, a: S) -> None: pass | |
| [out] | |
| [case testOverridingMethodInMultilevelHierarchyOfGenericTypes] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| U = TypeVar('U') | |
| V = TypeVar('V') | |
| class D: pass | |
| class C(Generic[T, U, V]): | |
| def f(self, a: V) -> None: pass | |
| def g(self, a: V) -> None: pass | |
| class B(C[D, D, T], Generic[T]): pass | |
| class A(B[S], Generic[T, S]): | |
| def f(self, a: T) -> None: pass \ | |
| # E: Argument 1 of "f" is incompatible with supertype "C"; supertype defines the argument type as "S" \ | |
| # N: This violates the Liskov substitution principle \ | |
| # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides | |
| def g(self, a: S) -> None: pass | |
| [out] | |
| [case testOverrideGenericMethodInNonGenericClass] | |
| from typing import TypeVar | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| class A: | |
| def f(self, x: T, y: S) -> None: pass | |
| class B(A): | |
| def f(self, x: S, y: T) -> None: pass | |
| class C(A): | |
| # Okay, because T = object allows any type for the arguments. | |
| def f(self, x: T, y: T) -> None: pass | |
| [case testOverrideGenericMethodInNonGenericClassLists] | |
| from typing import TypeVar, List | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| class A: | |
| def f(self, x: List[T], y: List[S]) -> None: pass | |
| class B(A): | |
| def f(self, x: List[S], y: List[T]) -> None: pass | |
| class C(A): | |
| def f(self, x: List[T], y: List[T]) -> None: pass # Fail | |
| [builtins fixtures/list.pyi] | |
| [out] | |
| main:11: error: Signature of "f" incompatible with supertype "A" | |
| main:11: note: Superclass: | |
| main:11: note: def [T, S] f(self, x: list[T], y: list[S]) -> None | |
| main:11: note: Subclass: | |
| main:11: note: def [T] f(self, x: list[T], y: list[T]) -> None | |
| [case testOverrideGenericMethodInNonGenericClassGeneralize] | |
| from typing import TypeVar | |
| T = TypeVar('T') | |
| T1 = TypeVar('T1', bound=str) | |
| S = TypeVar('S') | |
| class A: | |
| def f(self, x: int, y: S) -> None: pass | |
| class B(A): | |
| def f(self, x: T, y: S) -> None: pass | |
| class C(A): | |
| def f(self, x: T, y: str) -> None: pass | |
| class D(A): | |
| def f(self, x: T1, y: S) -> None: pass # TODO: This error could be more specific. | |
| [out] | |
| main:12: error: Argument 2 of "f" is incompatible with supertype "A"; supertype defines the argument type as "S" | |
| main:12: note: This violates the Liskov substitution principle | |
| main:12: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides | |
| main:14: error: Signature of "f" incompatible with supertype "A" | |
| main:14: note: Superclass: | |
| main:14: note: def [S] f(self, x: int, y: S) -> None | |
| main:14: note: Subclass: | |
| main:14: note: def [T1: str, S] f(self, x: T1, y: S) -> None | |
| -- Inheritance from generic types with implicit dynamic supertype | |
| -- -------------------------------------------------------------- | |
| [case testInheritanceFromGenericWithImplicitDynamicAndSubtyping] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| a: A | |
| bc: B[C] | |
| bd: B[D] | |
| if int(): | |
| a = bc # E: Incompatible types in assignment (expression has type "B[C]", variable has type "A") | |
| bc = a | |
| bd = a | |
| class B(Generic[T]): pass | |
| class A(B): pass | |
| class C: pass | |
| class D: pass | |
| [out] | |
| [case testInheritanceFromGenericWithImplicitDynamicAndExternalAccess] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| class B(Generic[T]): | |
| def f(self, a: 'B[T]') -> None: pass | |
| def __init__(self, x: 'B[T]') -> None: | |
| self.x = x | |
| class A(B): pass | |
| class C: pass | |
| a: A | |
| c: C | |
| bc: B[C] | |
| a.x = c # E: Incompatible types in assignment (expression has type "C", variable has type "B[Any]") | |
| a.f(c) # E: Argument 1 to "f" of "B" has incompatible type "C"; expected "B[Any]" | |
| a.x = bc | |
| a.f(bc) | |
| [out] | |
| [case testInheritanceFromGenericWithImplicitDynamic] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| a: A | |
| c: C | |
| bc: B[C] | |
| class B(Generic[T]): | |
| def f(self, a: 'B[T]') -> None: pass | |
| def __init__(self, x: 'B[T]') -> None: | |
| self.x = x | |
| class A(B): | |
| def g(self) -> None: | |
| self.x = c # E: Incompatible types in assignment (expression has type "C", variable has type "B[Any]") | |
| self.f(c) # E: Argument 1 to "f" of "B" has incompatible type "C"; expected "B[Any]" | |
| self.x = bc | |
| self.f(bc) | |
| class C: pass | |
| [out] | |
| [case testInheritanceFromGenericWithImplicitDynamicAndOverriding] | |
| from typing import TypeVar, Generic, Tuple | |
| T = TypeVar('T') | |
| class B(Generic[T]): | |
| def f(self, a: T, b: 'Tuple[T, B[T]]') -> None: | |
| pass | |
| class A(B): | |
| def f(self, a, b): pass | |
| [builtins fixtures/tuple.pyi] | |
| [out] | |
| -- Inheritance from generic types and super expressions | |
| -- ---------------------------------------------------- | |
| [case testSuperExpressionsWhenInheritingFromGenericType] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| class B(Generic[T]): | |
| def f(self, a: T) -> None: pass | |
| class A(B[S], Generic[T, S]): | |
| def g(self, t: T, s: S) -> None: | |
| super().f(t) # E: Argument 1 to "f" of "B" has incompatible type "T"; expected "S" | |
| super().f(s) | |
| [out] | |
| [case testSuperExpressionsWhenInheritingFromGenericTypeAndDeepHierarchy] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| U = TypeVar('U') | |
| V = TypeVar('V') | |
| class C(Generic[T, U, V]): | |
| def f(self, a: V) -> None: pass | |
| class D: pass | |
| class B(C[D, D, T], Generic[T]): pass | |
| class A(B[S], Generic[T, S]): | |
| def g(self, t: T, s: S) -> None: | |
| super().f(t) # E: Argument 1 to "f" of "C" has incompatible type "T"; expected "S" | |
| super().f(s) | |
| [out] | |
| -- Type of inherited constructor | |
| -- ----------------------------- | |
| [case testInheritedConstructor] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| class A(Generic[T]): | |
| def __init__(self, x: T) -> None: pass | |
| class B(A[T], Generic[T]): pass | |
| class C(A[int]): pass | |
| class D(A[A[T]], Generic[T]): pass | |
| B(1) | |
| C(1) | |
| C('a') # E: Argument 1 to "C" has incompatible type "str"; expected "int" | |
| D(A(1)) | |
| D(1) # E: Argument 1 to "D" has incompatible type "int"; expected "A[Never]" | |
| [case testInheritedConstructor2] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| U = TypeVar('U') | |
| Z = TypeVar('Z') | |
| class A(Generic[T, U]): | |
| def __init__(self, x: T, y: U, z: Z) -> None: pass | |
| class B(A[int, T], Generic[T]): pass | |
| class C(B[A[T, str]], Generic[T, U]): pass | |
| # C[T, U] <: B[A[T, str]] <: A[int, A[T, str]] | |
| C(1, A(1, 'a', 0), 'z') | |
| C(1, A('1', 'a', 0), 'z') | |
| C('1', A(1, 'a', 0), 'z') # E: Argument 1 to "C" has incompatible type "str"; expected "int" | |
| C(1, A(1, 1, 0), 'z') # E: Argument 2 to "A" has incompatible type "int"; expected "str" | |
| -- Subtyping with a generic abstract base class | |
| -- -------------------------------------------- | |
| [case testSubtypingWithGenericTypeSubclassingGenericAbstractClass] | |
| from typing import TypeVar, Generic | |
| from abc import abstractmethod | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| acd: A[C, D] | |
| adc: A[D, C] | |
| ic: I[C] | |
| id: I[D] | |
| if int(): | |
| ic = acd # E: Incompatible types in assignment (expression has type "A[C, D]", variable has type "I[C]") | |
| id = adc # E: Incompatible types in assignment (expression has type "A[D, C]", variable has type "I[D]") | |
| adc = ic # E: Incompatible types in assignment (expression has type "I[C]", variable has type "A[D, C]") | |
| if int(): | |
| ic = adc | |
| id = acd | |
| class I(Generic[T]): | |
| @abstractmethod | |
| def f(self): pass | |
| class A(I[S], Generic[T, S]): pass | |
| class C: pass | |
| class D: pass | |
| [case testSubtypingWithTypeImplementingGenericABCViaInheritance] | |
| from typing import TypeVar, Generic | |
| S = TypeVar('S') | |
| a: A | |
| b: B | |
| ic: I[C] | |
| id: I[D] | |
| ie: I[E] | |
| class I(Generic[S]): pass | |
| class B(I[C]): pass | |
| class A(B): pass | |
| if int(): | |
| ie = a # E: Incompatible types in assignment (expression has type "A", variable has type "I[E]") | |
| a = ic # E: Incompatible types in assignment (expression has type "I[C]", variable has type "A") | |
| if int(): | |
| a = id # E: Incompatible types in assignment (expression has type "I[D]", variable has type "A") | |
| if int(): | |
| a = b # E: Incompatible types in assignment (expression has type "B", variable has type "A") | |
| id = a # E: Incompatible types in assignment (expression has type "A", variable has type "I[D]") | |
| ic = a | |
| b = a | |
| class C: pass | |
| class D: pass | |
| class E: pass | |
| [builtins fixtures/tuple.pyi] | |
| [out] | |
| [case testSubtypingWithTypeImplementingGenericABCViaInheritance2-skip] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| class I(Generic[T]): pass | |
| class A(I[C]): pass | |
| class B(A, I[D]): pass # Fail | |
| class C: pass | |
| class D: pass | |
| [out] | |
| main:5: error: Class "B" has base "I" duplicated inconsistently | |
| [case testSubtypingAndABCExtension] | |
| from typing import TypeVar, Generic | |
| from abc import abstractmethod, ABCMeta | |
| t = TypeVar('t') | |
| a: A[object] | |
| i: I[object] | |
| j: J[object] | |
| (ii, jj) = (i, j) | |
| if int(): | |
| ii = a | |
| jj = a | |
| if int(): | |
| jj = i | |
| a = i # E: Incompatible types in assignment (expression has type "I[object]", variable has type "A[object]") | |
| if int(): | |
| a = j # E: Incompatible types in assignment (expression has type "J[object]", variable has type "A[object]") | |
| class J(Generic[t]): pass | |
| class X(metaclass=ABCMeta): pass | |
| class I(X, J[t], Generic[t]): pass | |
| class A(I[t], Generic[t]): pass | |
| [builtins fixtures/tuple.pyi] | |
| -- Subclassing a generic ABC | |
| -- ------------------------- | |
| [case testSubclassingGenericABC1] | |
| from typing import TypeVar, Generic | |
| from abc import abstractmethod | |
| T = TypeVar('T') | |
| class I(Generic[T]): | |
| @abstractmethod | |
| def f(self, a: T) -> None: pass | |
| @abstractmethod | |
| def g(self, a: T) -> None: pass | |
| class A(I[C]): | |
| def f(self, a: 'D') -> None: pass \ | |
| # E: Argument 1 of "f" is incompatible with supertype "I"; supertype defines the argument type as "C" \ | |
| # N: This violates the Liskov substitution principle \ | |
| # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides | |
| def g(self, a: 'C') -> None: pass | |
| class C: pass | |
| class D: pass | |
| [out] | |
| -- Extending a generic ABC with deep type hierarchy | |
| -- ------------------------------------------------ | |
| [case testSubclassingGenericABCWithDeepHierarchy] | |
| from typing import Any, TypeVar, Generic | |
| from abc import abstractmethod | |
| T = TypeVar('T') | |
| a: A | |
| ic: I[C] | |
| id: I[D] | |
| if int(): | |
| id = a # E: Incompatible types in assignment (expression has type "A", variable has type "I[D]") | |
| ic = a | |
| class I(Generic[T]): | |
| @abstractmethod | |
| def f(self, a: T, b: T) -> None: pass | |
| @abstractmethod | |
| def g(self, a: T, b: 'D') -> None: pass | |
| class B(I[C]): | |
| def f(self, a: 'C', b: 'C') -> None: pass | |
| def g(self, a: 'C', b: Any) -> None: pass | |
| class A(B): | |
| def g(self, a: 'C', b: 'C') -> None: pass \ | |
| # E: Argument 2 of "g" is incompatible with supertype "I"; supertype defines the argument type as "D" \ | |
| # N: This violates the Liskov substitution principle \ | |
| # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides | |
| def f(self, a: 'C', b: 'C') -> None: pass | |
| class C: pass | |
| class D: pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testSubclassingGenericABCWithDeepHierarchy2] | |
| from typing import Any, TypeVar, Generic | |
| from abc import abstractmethod | |
| T = TypeVar('T') | |
| class I(Generic[T]): | |
| @abstractmethod | |
| def f(self, a: T, b: T) -> None: pass | |
| class B(I[C]): | |
| def f(self, a: 'C', b: Any) -> None: pass | |
| class A(B): | |
| def f(self, a: 'C', b: 'D') -> None: pass \ | |
| # E: Argument 2 of "f" is incompatible with supertype "I"; supertype defines the argument type as "C" \ | |
| # N: This violates the Liskov substitution principle \ | |
| # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides | |
| class C: pass | |
| class D: pass | |
| [out] | |
| -- Implicit Any types and subclassing generic ABC | |
| -- ---------------------------------------------- | |
| [case testSubclassingGenericABCWithImplicitAny] | |
| from typing import Any, TypeVar, Generic | |
| from abc import abstractmethod | |
| T = TypeVar('T') | |
| a: Any | |
| ic: I[C] | |
| id: I[D] | |
| ic = a | |
| id = a | |
| class I(Generic[T]): | |
| @abstractmethod | |
| def f(self, a: T) -> None: pass | |
| class A(I): | |
| def f(self, a): pass | |
| class C: pass | |
| class D: pass | |
| [case testSubclassingGenericABCWithImplicitAnyAndDeepHierarchy] | |
| from typing import Any, TypeVar, Generic | |
| from abc import abstractmethod | |
| T = TypeVar('T') | |
| a: Any | |
| ic: I[C] | |
| id: I[D] | |
| ic = a | |
| id = a | |
| class I(Generic[T]): | |
| @abstractmethod | |
| def f(self, a: T, b: T) -> None: pass | |
| class B(I): | |
| def f(self, a, b): pass | |
| class A(B): | |
| def f(self, a: 'C', b: 'D') -> None: pass | |
| class C: pass | |
| class D: pass | |
| [case testImplementingGenericABCWithImplicitAnyAndDeepHierarchy2] | |
| from typing import Any, TypeVar, Generic | |
| from abc import abstractmethod | |
| T = TypeVar('T') | |
| a: Any | |
| jc: J[C] | |
| jd: J[D] | |
| jc = a | |
| jd = a | |
| class J(Generic[T]): | |
| @abstractmethod | |
| def f(self, a: T, b: T) -> None: pass | |
| class I(J): | |
| @abstractmethod | |
| def f(self, a, b): pass | |
| class A(I): | |
| def f(self, a: 'C', b: 'D') -> None: pass | |
| class C: pass | |
| class D: pass | |
| -- Accessing generic ABC members | |
| -- ----------------------------- | |
| [case testAccessingGenericABCMembers] | |
| from typing import TypeVar, Generic | |
| from abc import abstractmethod | |
| T = TypeVar('T') | |
| class I(Generic[T]): | |
| @abstractmethod | |
| def f(self, a: T) -> None: pass | |
| class A: pass | |
| class B: pass | |
| a: A | |
| b: B | |
| ia: I[A] | |
| ia.f(b) # E: Argument 1 to "f" of "I" has incompatible type "B"; expected "A" | |
| ia.f(a) | |
| [builtins fixtures/tuple.pyi] | |
| [case testAccessingInheritedGenericABCMembers] | |
| from typing import TypeVar, Generic | |
| from abc import abstractmethod | |
| T = TypeVar('T') | |
| class J(Generic[T]): | |
| @abstractmethod | |
| def f(self, a: T) -> None: pass | |
| class I(J[T], Generic[T]): pass | |
| class A: pass | |
| class B: pass | |
| a: A | |
| b: B | |
| ia: I[A] | |
| ia.f(b) # E: Argument 1 to "f" of "J" has incompatible type "B"; expected "A" | |
| ia.f(a) | |
| [builtins fixtures/tuple.pyi] | |
| -- Misc | |
| -- ---- | |
| [case testMultipleAssignmentAndGenericSubtyping] | |
| from typing import Iterable | |
| n: int | |
| s: str | |
| class Nums(Iterable[int]): | |
| def __iter__(self): pass | |
| def __next__(self): pass | |
| n, n = Nums() | |
| s, s = Nums() # E: Incompatible types in assignment (expression has type "int", variable has type "str") | |
| [builtins fixtures/for.pyi] | |
| [out] | |
| [case testUninhabitedCacheChecksAmbiguous] | |
| # https://github.com/python/mypy/issues/19641 | |
| from typing import Mapping, Never, TypeVar | |
| M = TypeVar("M", bound=Mapping[str,object]) | |
| def get(arg: M, /) -> M: | |
| return arg | |
| get({}) | |
| def upcast(d: dict[Never, Never]) -> Mapping[str, object]: | |
| return d # E: Incompatible return value type (got "dict[Never, Never]", expected "Mapping[str, object]") | |
| [builtins fixtures/dict.pyi] | |
| -- Variance | |
| -- -------- | |
| [case testCovariant] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T', covariant=True) | |
| class G(Generic[T]): pass | |
| class A: pass | |
| class B(A): pass | |
| class C(B): pass | |
| a: G[A] | |
| b: G[B] | |
| c: G[C] | |
| if int(): | |
| b = a # E: Incompatible types in assignment (expression has type "G[A]", variable has type "G[B]") | |
| b = c | |
| [builtins fixtures/bool.pyi] | |
| [out] | |
| [case testContravariant] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T', contravariant=True) | |
| class G(Generic[T]): pass | |
| class A: pass | |
| class B(A): pass | |
| class C(B): pass | |
| a: G[A] | |
| b: G[B] | |
| c: G[C] | |
| if int(): | |
| b = a | |
| b = c # E: Incompatible types in assignment (expression has type "G[C]", variable has type "G[B]") | |
| [builtins fixtures/bool.pyi] | |
| [out] | |
| [case testInvariant] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') # invariant (default) | |
| class G(Generic[T]): pass | |
| class A: pass | |
| class B(A): pass | |
| class C(B): pass | |
| a: G[A] | |
| b: G[B] | |
| c: G[C] | |
| if int(): | |
| b = a # E: Incompatible types in assignment (expression has type "G[A]", variable has type "G[B]") | |
| b = c # E: Incompatible types in assignment (expression has type "G[C]", variable has type "G[B]") | |
| [builtins fixtures/bool.pyi] | |
| [out] | |
| [case testTypeVarSubtypeUnion] | |
| from typing import Union, TypeVar, Generic | |
| class U: pass | |
| class W: pass | |
| T = TypeVar('T', bound=Union[U, W]) | |
| class Y(Generic[T]): | |
| def __init__(self) -> None: | |
| pass | |
| def f(self) -> T: | |
| return U() # E: Incompatible return value type (got "U", expected "T") | |
| [case testTypeVarBoundToOldUnionAttributeAccess] | |
| from typing import Union, TypeVar | |
| class U: | |
| a: float | |
| class V: | |
| b: float | |
| class W: | |
| c: float | |
| T = TypeVar("T", bound=Union[U, V, W]) | |
| def f(x: T) -> None: | |
| x.a # E | |
| x.b = 1.0 # E | |
| del x.c # E | |
| [out] | |
| main:13: error: Item "V" of the upper bound "U | V | W" of type variable "T" has no attribute "a" | |
| main:13: error: Item "W" of the upper bound "U | V | W" of type variable "T" has no attribute "a" | |
| main:14: error: Item "U" of the upper bound "U | V | W" of type variable "T" has no attribute "b" | |
| main:14: error: Item "W" of the upper bound "U | V | W" of type variable "T" has no attribute "b" | |
| main:15: error: Item "U" of the upper bound "U | V | W" of type variable "T" has no attribute "c" | |
| main:15: error: Item "V" of the upper bound "U | V | W" of type variable "T" has no attribute "c" | |
| [case testTypeVarBoundToNewUnionAttributeAccess] | |
| from typing import TypeVar | |
| class U: | |
| a: int | |
| class V: | |
| b: int | |
| class W: | |
| c: int | |
| T = TypeVar("T", bound=U | V | W) | |
| def f(x: T) -> None: | |
| x.a # E | |
| x.b = 1 # E | |
| del x.c # E | |
| [builtins fixtures/tuple.pyi] | |
| [out] | |
| main:13: error: Item "V" of the upper bound "U | V | W" of type variable "T" has no attribute "a" | |
| main:13: error: Item "W" of the upper bound "U | V | W" of type variable "T" has no attribute "a" | |
| main:14: error: Item "U" of the upper bound "U | V | W" of type variable "T" has no attribute "b" | |
| main:14: error: Item "W" of the upper bound "U | V | W" of type variable "T" has no attribute "b" | |
| main:15: error: Item "U" of the upper bound "U | V | W" of type variable "T" has no attribute "c" | |
| main:15: error: Item "V" of the upper bound "U | V | W" of type variable "T" has no attribute "c" | |
| [case testSubtypingIterableUnpacking1] | |
| # https://github.com/python/mypy/issues/11138 | |
| from typing import Generic, Iterator, TypeVar | |
| T = TypeVar("T") | |
| U = TypeVar("U") | |
| class X1(Iterator[U], Generic[T, U]): | |
| pass | |
| x1: X1[str, int] | |
| reveal_type(list(x1)) # N: Revealed type is "builtins.list[builtins.int]" | |
| reveal_type([*x1]) # N: Revealed type is "builtins.list[builtins.int]" | |
| class X2(Iterator[T], Generic[T, U]): | |
| pass | |
| x2: X2[str, int] | |
| reveal_type(list(x2)) # N: Revealed type is "builtins.list[builtins.str]" | |
| reveal_type([*x2]) # N: Revealed type is "builtins.list[builtins.str]" | |
| class X3(Generic[T, U], Iterator[U]): | |
| pass | |
| x3: X3[str, int] | |
| reveal_type(list(x3)) # N: Revealed type is "builtins.list[builtins.int]" | |
| reveal_type([*x3]) # N: Revealed type is "builtins.list[builtins.int]" | |
| class X4(Generic[T, U], Iterator[T]): | |
| pass | |
| x4: X4[str, int] | |
| reveal_type(list(x4)) # N: Revealed type is "builtins.list[builtins.str]" | |
| reveal_type([*x4]) # N: Revealed type is "builtins.list[builtins.str]" | |
| class X5(Iterator[T]): | |
| pass | |
| x5: X5[str] | |
| reveal_type(list(x5)) # N: Revealed type is "builtins.list[builtins.str]" | |
| reveal_type([*x5]) # N: Revealed type is "builtins.list[builtins.str]" | |
| class X6(Generic[T, U], Iterator[bool]): | |
| pass | |
| x6: X6[str, int] | |
| reveal_type(list(x6)) # N: Revealed type is "builtins.list[builtins.bool]" | |
| reveal_type([*x6]) # N: Revealed type is "builtins.list[builtins.bool]" | |
| [builtins fixtures/list.pyi] | |
| [case testSubtypingIterableUnpacking2] | |
| from typing import Generic, Iterator, TypeVar, Mapping | |
| T = TypeVar("T") | |
| U = TypeVar("U") | |
| class X1(Generic[T, U], Iterator[U], Mapping[U, T]): | |
| pass | |
| x1: X1[str, int] | |
| reveal_type(list(x1)) # N: Revealed type is "builtins.list[builtins.int]" | |
| reveal_type([*x1]) # N: Revealed type is "builtins.list[builtins.int]" | |
| class X2(Generic[T, U], Iterator[U], Mapping[T, U]): | |
| pass | |
| x2: X2[str, int] | |
| reveal_type(list(x2)) # N: Revealed type is "builtins.list[builtins.int]" | |
| reveal_type([*x2]) # N: Revealed type is "builtins.list[builtins.int]" | |
| [builtins fixtures/list.pyi] | |
| [case testSubtypingMappingUnpacking1] | |
| # https://github.com/python/mypy/issues/11138 | |
| from typing import Generic, TypeVar, Mapping | |
| T = TypeVar("T") | |
| U = TypeVar("U") | |
| class X1(Generic[T, U], Mapping[U, T]): | |
| pass | |
| x1: X1[str, int] | |
| reveal_type(iter(x1)) # N: Revealed type is "typing.Iterator[builtins.int]" | |
| reveal_type({**x1}) # N: Revealed type is "builtins.dict[builtins.int, builtins.str]" | |
| class X2(Generic[T, U], Mapping[T, U]): | |
| pass | |
| x2: X2[str, int] | |
| reveal_type(iter(x2)) # N: Revealed type is "typing.Iterator[builtins.str]" | |
| reveal_type({**x2}) # N: Revealed type is "builtins.dict[builtins.str, builtins.int]" | |
| class X3(Generic[T, U], Mapping[bool, float]): | |
| pass | |
| x3: X3[str, int] | |
| reveal_type(iter(x3)) # N: Revealed type is "typing.Iterator[builtins.bool]" | |
| reveal_type({**x3}) # N: Revealed type is "builtins.dict[builtins.bool, builtins.float]" | |
| [builtins fixtures/dict.pyi] | |
| [case testSubtypingMappingUnpacking2] | |
| from typing import Generic, TypeVar, Mapping | |
| T = TypeVar("T") | |
| U = TypeVar("U") | |
| class X1(Generic[T, U], Mapping[U, T]): | |
| pass | |
| def func_with_kwargs(**kwargs: int): | |
| pass | |
| x1: X1[str, int] | |
| reveal_type(iter(x1)) | |
| reveal_type({**x1}) | |
| func_with_kwargs(**x1) | |
| [out] | |
| main:12: note: Revealed type is "typing.Iterator[builtins.int]" | |
| main:13: note: Revealed type is "builtins.dict[builtins.int, builtins.str]" | |
| main:14: error: Argument after ** must have string keys | |
| main:14: error: Argument 1 to "func_with_kwargs" has incompatible type "**X1[str, int]"; expected "int" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testSubtypingMappingUnpacking3] | |
| from typing import Generic, TypeVar, Mapping, Iterable | |
| T = TypeVar("T") | |
| U = TypeVar("U") | |
| class X1(Generic[T, U], Mapping[U, T], Iterable[U]): | |
| pass | |
| x1: X1[str, int] | |
| reveal_type(iter(x1)) # N: Revealed type is "typing.Iterator[builtins.int]" | |
| reveal_type({**x1}) # N: Revealed type is "builtins.dict[builtins.int, builtins.str]" | |
| # Some people would expect this to raise an error, but this currently does not: | |
| # `Mapping` has `Iterable[U]` base class, `X2` has direct `Iterable[T]` base class. | |
| # It would be impossible to define correct `__iter__` method for incompatible `T` and `U`. | |
| class X2(Generic[T, U], Mapping[U, T], Iterable[T]): | |
| pass | |
| x2: X2[str, int] | |
| reveal_type(iter(x2)) # N: Revealed type is "typing.Iterator[builtins.int]" | |
| reveal_type({**x2}) # N: Revealed type is "builtins.dict[builtins.int, builtins.str]" | |
| [builtins fixtures/dict.pyi] | |
| [case testNotDirectIterableAndMappingSubtyping] | |
| from typing import Generic, TypeVar, Dict, Iterable, Iterator, List | |
| T = TypeVar("T") | |
| U = TypeVar("U") | |
| class X1(Generic[T, U], Dict[U, T], Iterable[U]): | |
| def __iter__(self) -> Iterator[U]: pass | |
| x1: X1[str, int] | |
| reveal_type(iter(x1)) # N: Revealed type is "typing.Iterator[builtins.int]" | |
| reveal_type({**x1}) # N: Revealed type is "builtins.dict[builtins.int, builtins.str]" | |
| class X2(Generic[T, U], List[U]): | |
| def __iter__(self) -> Iterator[U]: pass | |
| x2: X2[str, int] | |
| reveal_type(iter(x2)) # N: Revealed type is "typing.Iterator[builtins.int]" | |
| reveal_type([*x2]) # N: Revealed type is "builtins.list[builtins.int]" | |
| [builtins fixtures/dict.pyi] | |
| [case testIncompatibleVariance] | |
| from typing import TypeVar, Generic | |
| T = TypeVar('T') | |
| T_co = TypeVar('T_co', covariant=True) | |
| T_contra = TypeVar('T_contra', contravariant=True) | |
| class A(Generic[T_co]): ... | |
| class B(A[T_contra], Generic[T_contra]): ... # E: Variance of TypeVar "T_contra" incompatible with variance in parent type | |
| class C(Generic[T_contra]): ... | |
| class D(C[T_co], Generic[T_co]): ... # E: Variance of TypeVar "T_co" incompatible with variance in parent type | |
| class E(Generic[T]): ... | |
| class F(E[T_co], Generic[T_co]): ... # E: Variance of TypeVar "T_co" incompatible with variance in parent type | |
| class G(Generic[T]): ... | |
| class H(G[T_contra], Generic[T_contra]): ... # E: Variance of TypeVar "T_contra" incompatible with variance in parent type | |
| [case testParameterizedGenericOverrideWithProperty] | |
| from typing import TypeVar, Generic | |
| T = TypeVar("T") | |
| class A(Generic[T]): | |
| def __init__(self, val: T): | |
| self.member: T = val | |
| class B(A[str]): | |
| member: str | |
| class GoodPropertyOverride(A[str]): | |
| @property | |
| def member(self) -> str: ... | |
| @member.setter | |
| def member(self, val: str): ... | |
| class BadPropertyOverride(A[str]): | |
| @property # E: Signature of "member" incompatible with supertype "A" \ | |
| # N: Superclass: \ | |
| # N: str \ | |
| # N: Subclass: \ | |
| # N: int | |
| def member(self) -> int: ... | |
| @member.setter | |
| def member(self, val: int): ... | |
| class BadGenericPropertyOverride(A[str], Generic[T]): | |
| @property # E: Signature of "member" incompatible with supertype "A" \ | |
| # N: Superclass: \ | |
| # N: str \ | |
| # N: Subclass: \ | |
| # N: T | |
| def member(self) -> T: ... | |
| @member.setter | |
| def member(self, val: T): ... | |
| [builtins fixtures/property.pyi] | |
| [case testParameterizedGenericPropertyOverrideWithProperty] | |
| from typing import TypeVar, Generic | |
| T = TypeVar("T") | |
| class A(Generic[T]): | |
| @property | |
| def member(self) -> T: ... | |
| @member.setter | |
| def member(self, val: T): ... | |
| class B(A[str]): | |
| member: str | |
| class GoodPropertyOverride(A[str]): | |
| @property | |
| def member(self) -> str: ... | |
| @member.setter | |
| def member(self, val: str): ... | |
| class BadPropertyOverride(A[str]): | |
| @property # E: Signature of "member" incompatible with supertype "A" \ | |
| # N: Superclass: \ | |
| # N: str \ | |
| # N: Subclass: \ | |
| # N: int | |
| def member(self) -> int: ... | |
| @member.setter | |
| def member(self, val: int): ... | |
| class BadGenericPropertyOverride(A[str], Generic[T]): | |
| @property # E: Signature of "member" incompatible with supertype "A" \ | |
| # N: Superclass: \ | |
| # N: str \ | |
| # N: Subclass: \ | |
| # N: T | |
| def member(self) -> T: ... | |
| @member.setter | |
| def member(self, val: T): ... | |
| [builtins fixtures/property.pyi] | |
| [case testParameterizedGenericOverrideSelfWithProperty] | |
| from typing_extensions import Self | |
| class A: | |
| def __init__(self, val: Self): | |
| self.member: Self = val | |
| class GoodPropertyOverride(A): | |
| @property | |
| def member(self) -> "GoodPropertyOverride": ... | |
| @member.setter | |
| def member(self, val: "GoodPropertyOverride"): ... | |
| class GoodPropertyOverrideSelf(A): | |
| @property | |
| def member(self) -> Self: ... | |
| @member.setter | |
| def member(self, val: Self): ... | |
| [builtins fixtures/property.pyi] | |
| [case testParameterizedGenericOverrideWithSelfProperty] | |
| from typing import TypeVar, Generic | |
| from typing_extensions import Self | |
| T = TypeVar("T") | |
| class A(Generic[T]): | |
| def __init__(self, val: T): | |
| self.member: T = val | |
| class B(A["B"]): | |
| member: Self | |
| class GoodPropertyOverride(A["GoodPropertyOverride"]): | |
| @property | |
| def member(self) -> Self: ... | |
| @member.setter | |
| def member(self, val: Self): ... | |
| [builtins fixtures/property.pyi] | |
| [case testMultipleInheritanceCompatibleTypeVar] | |
| from typing import Generic, TypeVar | |
| T = TypeVar("T") | |
| U = TypeVar("U") | |
| class A(Generic[T]): | |
| x: T | |
| def fn(self, t: T) -> None: ... | |
| class A2(A[T]): | |
| y: str | |
| z: str | |
| class B(Generic[T]): | |
| x: T | |
| def fn(self, t: T) -> None: ... | |
| class C1(A2[str], B[str]): pass | |
| class C2(A2[str], B[int]): pass # E: Definition of "fn" in base class "A" is incompatible with definition in base class "B" \ | |
| # E: Definition of "x" in base class "A" is incompatible with definition in base class "B" | |
| class C3(A2[T], B[T]): pass | |
| class C4(A2[U], B[U]): pass | |
| class C5(A2[U], B[T]): pass # E: Definition of "fn" in base class "A" is incompatible with definition in base class "B" \ | |
| # E: Definition of "x" in base class "A" is incompatible with definition in base class "B" | |
| class D1(A[str], B[str]): pass | |
| class D2(A[str], B[int]): pass # E: Definition of "fn" in base class "A" is incompatible with definition in base class "B" \ | |
| # E: Definition of "x" in base class "A" is incompatible with definition in base class "B" | |
| class D3(A[T], B[T]): pass | |
| class D4(A[U], B[U]): pass | |
| class D5(A[U], B[T]): pass # E: Definition of "fn" in base class "A" is incompatible with definition in base class "B" \ | |
| # E: Definition of "x" in base class "A" is incompatible with definition in base class "B" | |
| [builtins fixtures/tuple.pyi] |