From ce8e1e13f2d0bb3dc2fdc97978c8e4a314a0f80f Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Thu, 11 Aug 2022 11:45:26 +0100 Subject: [PATCH 1/2] Fix daemon crashes related to ParamSpec and TypeVarTuple Fix daemon crash when using fine-grained caching and ParamSpec, with traceback like this (when using a compiled mypy): ``` Traceback (most recent call last): File "mypy/dmypy_server.py", line 230, in serve File "mypy/dmypy_server.py", line 273, in run_command File "mypy/dmypy_server.py", line 372, in cmd_recheck File "mypy/dmypy_server.py", line 529, in fine_grained_increment File "mypy/server/update.py", line 245, in update File "mypy/server/update.py", line 328, in update_one File "mypy/server/update.py", line 387, in update_module File "mypy/server/astdiff.py", line 158, in snapshot_symbol_table File "mypy/server/astdiff.py", line 236, in snapshot_type File "mypy/types.py", line 1173, in accept File "mypy/server/astdiff.py", line 300, in visit_instance File "mypy/nodes.py", line 2764, in fullname AttributeError: attribute 'TypeInfo' of '_fullname' undefined ``` Also fix TypeVarTuple crashes when using daemon. --- mypy/fixup.py | 8 +++ mypy/server/astdiff.py | 3 ++ mypy/test/testfinegrained.py | 1 + test-data/unit/fine-grained.test | 84 ++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+) diff --git a/mypy/fixup.py b/mypy/fixup.py index ed9361130529..6db3615c7574 100644 --- a/mypy/fixup.py +++ b/mypy/fixup.py @@ -11,10 +11,12 @@ FuncDef, MypyFile, OverloadedFuncDef, + ParamSpecExpr, SymbolTable, TypeAlias, TypeInfo, TypeVarExpr, + TypeVarTupleExpr, Var, ) from mypy.types import ( @@ -161,6 +163,12 @@ def visit_type_var_expr(self, tv: TypeVarExpr) -> None: value.accept(self.type_fixer) tv.upper_bound.accept(self.type_fixer) + def visit_paramspec_expr(self, p: ParamSpecExpr) -> None: + p.upper_bound.accept(self.type_fixer) + + def visit_type_var_tuple_expr(self, tv: TypeVarTupleExpr) -> None: + tv.upper_bound.accept(self.type_fixer) + def visit_var(self, v: Var) -> None: if self.current_info is not None: v.info = self.current_info diff --git a/mypy/server/astdiff.py b/mypy/server/astdiff.py index 5b7af991b5a0..a529039ce998 100644 --- a/mypy/server/astdiff.py +++ b/mypy/server/astdiff.py @@ -65,6 +65,7 @@ class level -- these are handled at attribute level (say, 'mod.Cls.method' TypeAlias, TypeInfo, TypeVarExpr, + TypeVarTupleExpr, Var, ) from mypy.types import ( @@ -186,6 +187,8 @@ def snapshot_symbol_table(name_prefix: str, table: SymbolTable) -> Dict[str, Sna ) elif isinstance(node, ParamSpecExpr): result[name] = ("ParamSpec", node.variance, snapshot_type(node.upper_bound)) + elif isinstance(node, TypeVarTupleExpr): + result[name] = ("TypeVarTuple", node.variance, snapshot_type(node.upper_bound)) else: assert symbol.kind != UNBOUND_IMPORTED if node and get_prefix(node.fullname) != name_prefix: diff --git a/mypy/test/testfinegrained.py b/mypy/test/testfinegrained.py index faf2a9ecc171..052fbacb2959 100644 --- a/mypy/test/testfinegrained.py +++ b/mypy/test/testfinegrained.py @@ -149,6 +149,7 @@ def get_options(self, source: str, testcase: DataDrivenTestCase, build_cache: bo options.use_fine_grained_cache = self.use_cache and not build_cache options.cache_fine_grained = self.use_cache options.local_partial_types = True + options.enable_incomplete_features = True if re.search("flags:.*--follow-imports", source) is None: # Override the default for follow_imports options.follow_imports = "error" diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test index 14acc8d1664e..b2ec9b83c0e5 100644 --- a/test-data/unit/fine-grained.test +++ b/test-data/unit/fine-grained.test @@ -9728,3 +9728,87 @@ x: str [builtins fixtures/dataclasses.pyi] [out] == + +[case testParamSpecCached] +import a + +[file a.py] +import b + +def f(x: int) -> str: return 'x' + +b.foo(f) + +[file a.py.2] +import b + +def f(x: int) -> str: return 'x' + +reveal_type(b.foo(f)) + +[file b.py] +from typing import TypeVar, Callable, Union +from typing_extensions import ParamSpec + +P = ParamSpec("P") +T = TypeVar("T") + +def foo(f: Callable[P, T]) -> Callable[P, Union[T, None]]: + return f + +[file b.py.2] +from typing import TypeVar, Callable, Union +from typing_extensions import ParamSpec + +P = ParamSpec("P") +T = TypeVar("T") + +def foo(f: Callable[P, T]) -> Callable[P, Union[T, None]]: + return f + +x = 0 # Arbitrary change to trigger reprocessing + +[builtins fixtures/dict.pyi] +[out] +== +a.py:5: note: Revealed type is "def (x: builtins.int) -> builtins.str" + +[case testTypeVarTupleCached] +import a + +[file a.py] +import b + +def f(x: int) -> str: return 'x' + +b.foo((1, 'x')) + +[file a.py.2] +import b + +reveal_type(b.foo((1, 'x'))) + +[file b.py] +from typing import Tuple +from typing_extensions import TypeVarTuple, Unpack + +Ts = TypeVarTuple("Ts") + +def foo(t: Tuple[Unpack[Ts]]) -> Tuple[Unpack[Ts]]: + return t + +[file b.py.2] +from typing import Tuple +from typing_extensions import TypeVarTuple, Unpack + +Ts = TypeVarTuple("Ts") + +def foo(t: Tuple[Unpack[Ts]]) -> Tuple[Unpack[Ts]]: + return t + +x = 0 # Arbitrary change to trigger reprocessing + +[builtins fixtures/dict.pyi] +[out] +== +a.py:3: note: Revealed type is "Tuple[Literal[1]?, Literal['x']?]" From 90bda9ba23b824205690376304a082851ef73650 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 23 Aug 2022 02:17:34 +0100 Subject: [PATCH 2/2] Fix merge --- test-data/unit/fine-grained.test | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test index 5207b1b5fc78..3a054e8fcfe5 100644 --- a/test-data/unit/fine-grained.test +++ b/test-data/unit/fine-grained.test @@ -9899,6 +9899,7 @@ def foo(t: Tuple[Unpack[Ts]]) -> Tuple[Unpack[Ts]]: x = 0 # Arbitrary change to trigger reprocessing [builtins fixtures/dict.pyi] [out] +== a.py:3: note: Revealed type is "Tuple[Literal[1]?, Literal['x']?]" [case testUnpackKwargsUpdateFine] @@ -9927,6 +9928,8 @@ def foo(**kwargs: Unpack[Person]): [file m.py] from lib import foo foo(name='Jennifer', age=38) + [builtins fixtures/dict.pyi] [out] -m.py:2: error: Argument "age" to "foo" has incompatible type "int"; expected "str" \ No newline at end of file +== +m.py:2: error: Argument "age" to "foo" has incompatible type "int"; expected "str"