Skip to content

Commit 27afa60

Browse files
JukkaLmsullivan
authored andcommitted
Fine-grained: Fix crashes when refreshing synthetic types (#4667)
Previously we only handled one kind of synthetic type, and others would cause a crash. Fixes #4665.
1 parent 6f9723c commit 27afa60

File tree

4 files changed

+52
-8
lines changed

4 files changed

+52
-8
lines changed

mypy/server/astmerge.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@
5555
)
5656
from mypy.traverser import TraverserVisitor
5757
from mypy.types import (
58-
Type, TypeVisitor, Instance, AnyType, NoneTyp, CallableType, DeletedType, PartialType,
58+
Type, SyntheticTypeVisitor, Instance, AnyType, NoneTyp, CallableType, DeletedType, PartialType,
5959
TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType,
60-
Overloaded, TypeVarDef, TypeList
60+
Overloaded, TypeVarDef, TypeList, CallableArgument, EllipsisType, StarType
6161
)
6262
from mypy.util import get_prefix
6363

@@ -320,7 +320,7 @@ def replace_statements(self, nodes: List[Statement]) -> List[Statement]:
320320
return result
321321

322322

323-
class TypeReplaceVisitor(TypeVisitor[None]):
323+
class TypeReplaceVisitor(SyntheticTypeVisitor[None]):
324324
"""Similar to NodeReplaceVisitor, but for type objects."""
325325

326326
def __init__(self, replacements: Dict[SymbolNode, SymbolNode]) -> None:
@@ -389,6 +389,15 @@ def visit_type_list(self, typ: TypeList) -> None:
389389
for item in typ.items:
390390
item.accept(self)
391391

392+
def visit_callable_argument(self, typ: CallableArgument) -> None:
393+
typ.typ.accept(self)
394+
395+
def visit_ellipsis_type(self, typ: EllipsisType) -> None:
396+
pass
397+
398+
def visit_star_type(self, typ: StarType) -> None:
399+
typ.type.accept(self)
400+
392401
def visit_uninhabited_type(self, typ: UninhabitedType) -> None:
393402
pass
394403

mypy/types.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ def __init__(self, items: List[Type], line: int = -1, column: int = -1) -> None:
255255
self.items = items
256256

257257
def accept(self, visitor: 'TypeVisitor[T]') -> T:
258+
assert isinstance(visitor, SyntheticTypeVisitor)
258259
return visitor.visit_type_list(self)
259260

260261
def serialize(self) -> JsonDict:
@@ -1506,11 +1507,6 @@ def visit_type_type(self, t: TypeType) -> T:
15061507
def visit_forwardref_type(self, t: ForwardRef) -> T:
15071508
raise RuntimeError('Internal error: unresolved forward reference')
15081509

1509-
def visit_type_list(self, t: TypeList) -> T:
1510-
# TODO: Do we need to implement this in more visitors? TypeList objects can
1511-
# exist as components of UnboundTypes.
1512-
raise self._notimplemented_helper('type_list')
1513-
15141510

15151511
class SyntheticTypeVisitor(TypeVisitor[T]):
15161512
"""A TypeVisitor that also knows how to visit synthetic AST constructs.

test-data/unit/fine-grained.test

+37
Original file line numberDiff line numberDiff line change
@@ -2598,3 +2598,40 @@ x = ''
25982598
b.py:5: error: Incompatible types in assignment (expression has type "int", base class "tuple" defined the type as "Callable[[Tuple[int, ...], Any], int]")
25992599
==
26002600
b.py:5: error: Incompatible types in assignment (expression has type "int", base class "tuple" defined the type as "Callable[[Tuple[int, ...], Any], int]")
2601+
2602+
[case testReprocessEllipses1]
2603+
import a
2604+
[file a.py]
2605+
from typing import Tuple
2606+
def foo(x: Tuple[int, ...]) -> None: pass
2607+
[file a.py.2]
2608+
from typing import Tuple
2609+
def foo(x: Tuple[int, ...]) -> None: pass
2610+
[builtins fixtures/tuple.pyi]
2611+
[out]
2612+
==
2613+
2614+
[case testReprocessEllipses2]
2615+
import a
2616+
[file a.py]
2617+
from typing import Callable
2618+
def foo(x: Callable[..., int]) -> None: pass
2619+
[file a.py.2]
2620+
from typing import Callable
2621+
def foo(x: Callable[..., int]) -> None: pass
2622+
[out]
2623+
==
2624+
2625+
[case testReprocessCallableArg]
2626+
import a
2627+
[file a.py]
2628+
from typing import Callable
2629+
from mypy_extensions import Arg
2630+
def a(f: Callable[[Arg(int, 'x')], int]) -> None: pass
2631+
[file a.py.2]
2632+
from typing import Callable
2633+
from mypy_extensions import Arg
2634+
def a(f: Callable[[Arg(int, 'x')], int]) -> None: pass
2635+
[builtins fixtures/dict.pyi]
2636+
[out]
2637+
==

test-data/unit/lib-stub/mypy_extensions.pyi

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# NOTE: Requires fixtures/dict.pyi
2+
13
from typing import Dict, Type, TypeVar, Optional, Any
24

35
_T = TypeVar('_T')

0 commit comments

Comments
 (0)