You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[PEP 695] Allow Self return types with contravariance (#17786)
Fix variance inference in this fragment from a typing conformance test:
```
class ClassA[T1, T2, T3](list[T1]):
def method1(self, a: T2) -> None:
...
def method2(self) -> T3:
...
```
Previously T2 was incorrectly inferred as invariant due to `list` having
methods that return `Self`. Be more flexible with return types to allow
inferring contravariance for type variables even if there are `Self`
return types, in particular.
We could probably make this even more lenient, but after thinking about
this for a while, I wasn't sure what the most general rule would be, so
I decided to just make a tweak to support the likely most common use
case (which is probably actually not that common either).
Link to conformance test:
https://github.com/python/typing/blob/main/conformance/tests/generics_variance_inference.py#L15C1-L20C12
inv3_2: Invariant3[int] = Invariant3[float](1) # E: Incompatible types in assignment (expression has type "Invariant3[float]", variable has type "Invariant3[int]")
394
394
[builtins fixtures/property.pyi]
395
395
396
+
[case testPEP695InferVarianceWithInheritedSelf]
397
+
from typing import overload, Self, TypeVar, Generic
398
+
399
+
T = TypeVar("T")
400
+
S = TypeVar("S")
401
+
402
+
class C(Generic[T]):
403
+
def f(self, x: T) -> Self: ...
404
+
def g(self) -> T: ...
405
+
406
+
class D[T1, T2](C[T1]):
407
+
def m(self, x: T2) -> None: ...
408
+
409
+
a1: D[int, int] = D[int, object]()
410
+
a2: D[int, object] = D[int, int]() # E: Incompatible types in assignment (expression has type "D[int, int]", variable has type "D[int, object]")
411
+
a3: D[int, int] = D[object, object]() # E: Incompatible types in assignment (expression has type "D[object, object]", variable has type "D[int, int]")
412
+
a4: D[object, int] = D[int, object]() # E: Incompatible types in assignment (expression has type "D[int, object]", variable has type "D[object, int]")
413
+
414
+
[case testPEP695InferVarianceWithReturnSelf]
415
+
from typing import Self, overload
416
+
417
+
class Cov[T]:
418
+
def f(self) -> Self: ...
419
+
420
+
a1: Cov[int] = Cov[float]() # E: Incompatible types in assignment (expression has type "Cov[float]", variable has type "Cov[int]")
421
+
a2: Cov[float] = Cov[int]()
422
+
423
+
class Contra[T]:
424
+
def f(self) -> Self: ...
425
+
def g(self, x: T) -> None: ...
426
+
427
+
b1: Contra[int] = Contra[float]()
428
+
b2: Contra[float] = Contra[int]() # E: Incompatible types in assignment (expression has type "Contra[int]", variable has type "Contra[float]")
429
+
430
+
class Cov2[T]:
431
+
@overload
432
+
def f(self, x): ...
433
+
@overload
434
+
def f(self) -> Self: ...
435
+
def f(self, x=None): ...
436
+
437
+
c1: Cov2[int] = Cov2[float]() # E: Incompatible types in assignment (expression has type "Cov2[float]", variable has type "Cov2[int]")
438
+
c2: Cov2[float] = Cov2[int]()
439
+
440
+
class Contra2[T]:
441
+
@overload
442
+
def f(self, x): ...
443
+
@overload
444
+
def f(self) -> Self: ...
445
+
def f(self, x=None): ...
446
+
447
+
def g(self, x: T) -> None: ...
448
+
449
+
d1: Contra2[int] = Contra2[float]()
450
+
d2: Contra2[float] = Contra2[int]() # E: Incompatible types in assignment (expression has type "Contra2[int]", variable has type "Contra2[float]")
0 commit comments