Skip to content

Commit

Permalink
Fix daemon crashes related to ParamSpec and TypeVarTuple (#13381)
Browse files Browse the repository at this point in the history
* 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.

Co-authored-by: Ivan Levkivskyi <levkivskyi@gmail.com>
  • Loading branch information
2 people authored and jhance committed Sep 9, 2022
1 parent 35bc1a2 commit 5d08c47
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 0 deletions.
8 changes: 8 additions & 0 deletions mypy/fixup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
FuncDef,
MypyFile,
OverloadedFuncDef,
ParamSpecExpr,
SymbolTable,
TypeAlias,
TypeInfo,
TypeVarExpr,
TypeVarTupleExpr,
Var,
)
from mypy.types import (
Expand Down Expand Up @@ -164,6 +166,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
Expand Down
3 changes: 3 additions & 0 deletions mypy/server/astdiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class level -- these are handled at attribute level (say, 'mod.Cls.method'
TypeAlias,
TypeInfo,
TypeVarExpr,
TypeVarTupleExpr,
Var,
)
from mypy.types import (
Expand Down Expand Up @@ -189,6 +190,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:
Expand Down
1 change: 1 addition & 0 deletions mypy/test/testfinegrained.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,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"
Expand Down
83 changes: 83 additions & 0 deletions test-data/unit/fine-grained.test
Original file line number Diff line number Diff line change
Expand Up @@ -9819,6 +9819,89 @@ x: str
[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']?]"

[case testUnpackKwargsUpdateFine]
# flags: --enable-incomplete-features
import m
Expand Down

0 comments on commit 5d08c47

Please sign in to comment.