From 442eccacf030f6463f85b045e18c956c9d16b671 Mon Sep 17 00:00:00 2001 From: Akuli Date: Sat, 29 Jan 2022 16:42:19 +0200 Subject: [PATCH 1/3] SubtypeVisitor: treat ParamSpec as if it was a covariant TypeVar --- mypy/subtypes.py | 3 +++ .../unit/check-parameter-specification.test | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 51a9dfbb8bc1..e7c3b428c721 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -277,6 +277,9 @@ def visit_instance(self, left: Instance) -> bool: if isinstance(tvar, TypeVarType): if not self.check_type_parameter(lefta, righta, tvar.variance): nominal = False + elif isinstance(tvar, ParamSpecType): + if not self.check_type_parameter(lefta, righta, COVARIANT): + nominal = False else: if not is_equivalent(lefta, righta): nominal = False diff --git a/test-data/unit/check-parameter-specification.test b/test-data/unit/check-parameter-specification.test index f2281babb193..96437c82c919 100644 --- a/test-data/unit/check-parameter-specification.test +++ b/test-data/unit/check-parameter-specification.test @@ -416,3 +416,26 @@ with f() as x: pass [builtins fixtures/dict.pyi] [typing fixtures/typing-full.pyi] + +[case testDecoratingClassesThatUseParamSpec] +from typing import Generic, TypeVar, Callable, Any +from typing_extensions import ParamSpec + +_P = ParamSpec("_P") +_T = TypeVar("_T") +_F = TypeVar("_F", bound=Callable[..., Any]) + +def f(x: _F) -> _F: ... + +@f # Should be ok +class OnlyParamSpec(Generic[_P]): + pass + +@f # Should be ok +class MixedWithTypeVar1(Generic[_P, _T]): + pass + +@f # Should be ok +class MixedWithTypeVar2(Generic[_T, _P]): + pass +[builtins fixtures/dict.pyi] From 272de9ad4ba2ef9a4215b6196e371777f680add1 Mon Sep 17 00:00:00 2001 From: Akuli Date: Sat, 9 Apr 2022 18:56:08 +0300 Subject: [PATCH 2/3] use is_equivalent for everything except TypeVar and ParamSpec --- mypy/subtypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index ba9d86f60cd6..087e10a04e6f 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -294,7 +294,7 @@ def visit_instance(self, left: Instance) -> bool: if not self.check_type_parameter(lefta, righta, COVARIANT): nominal = False else: - if not self.check_type_parameter(lefta, righta, COVARIANT): + if not is_equivalent(lefta, righta): nominal = False if nominal: TypeState.record_subtype_cache_entry(self._subtype_kind, left, right) From 2eb0fcc317b1b624154d4326e65a0c697b2ad7a9 Mon Sep 17 00:00:00 2001 From: Akuli Date: Sun, 10 Apr 2022 19:47:35 +0300 Subject: [PATCH 3/3] delete test added in separate pr --- .../unit/check-parameter-specification.test | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/test-data/unit/check-parameter-specification.test b/test-data/unit/check-parameter-specification.test index 827077e96b64..fe2354612fbb 100644 --- a/test-data/unit/check-parameter-specification.test +++ b/test-data/unit/check-parameter-specification.test @@ -416,29 +416,6 @@ with f() as x: [builtins fixtures/dict.pyi] [typing fixtures/typing-full.pyi] -[case testDecoratingClassesThatUseParamSpec] -from typing import Generic, TypeVar, Callable, Any -from typing_extensions import ParamSpec - -_P = ParamSpec("_P") -_T = TypeVar("_T") -_F = TypeVar("_F", bound=Callable[..., Any]) - -def f(x: _F) -> _F: ... - -@f # Should be ok -class OnlyParamSpec(Generic[_P]): - pass - -@f # Should be ok -class MixedWithTypeVar1(Generic[_P, _T]): - pass - -@f # Should be ok -class MixedWithTypeVar2(Generic[_T, _P]): - pass -[builtins fixtures/dict.pyi] - [case testParamSpecLiterals] from typing_extensions import ParamSpec, TypeAlias from typing import Generic, TypeVar