From 737caed89c22f2e91b4c09469ad59bdcd6e16d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Perrin?= Date: Thu, 10 Mar 2022 10:26:00 +0000 Subject: [PATCH 1/2] Test for undefined FuncDef.arguments after deserialize from cache --- test-data/unit/check-modules.test | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 6c32c088255d..4f7b9f322df1 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -3190,3 +3190,35 @@ from dir1 import * from .test2 import * [file dir1/test2.py] from test1 import aaaa # E: Module "test1" has no attribute "aaaa" + +[case testIncompatibleOverrideFromCachedModuleIncremental] +import b +[file a.py] +class Foo: + def frobnicate(self, *args, **kwargs): pass +[file b.py] +from a import Foo +class Bar(Foo): + def frobnicate(self) -> None: pass +[file b.py.2] +from a import Foo +class Bar(Foo): + def frobnicate(self, *args) -> None: pass +[file b.py.3] +from a import Foo +class Bar(Foo): + def frobnicate(self, *args) -> None: pass # type: ignore[override] # I know +[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[out1] +tmp/b.py:3: error: Signature of "frobnicate" incompatible with supertype "Foo" +tmp/b.py:3: note: Superclass: +tmp/b.py:3: note: def frobnicate(self, *args: Any, **kwargs: Any) -> Any +tmp/b.py:3: note: Subclass: +tmp/b.py:3: note: def frobnicate(self) -> None +[out2] +tmp/b.py:3: error: Signature of "frobnicate" incompatible with supertype "Foo" +tmp/b.py:3: note: Superclass: +tmp/b.py:3: note: def frobnicate(self, *args: Any, **kwargs: Any) -> Any +tmp/b.py:3: note: Subclass: +tmp/b.py:3: note: def frobnicate(self, *args: Any) -> None From 3e9f50e4bd63d279fafed480cfd2aaa53156563a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Perrin?= Date: Thu, 10 Mar 2022 10:28:16 +0000 Subject: [PATCH 2/2] Initialize FuncDef.arguments in deserialize --- mypy/nodes.py | 8 +++++--- mypy/types.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mypy/nodes.py b/mypy/nodes.py index f520280dce2d..1f374c38736f 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -641,7 +641,7 @@ def set_line(self, class FuncItem(FuncBase): """Base class for nodes usable as overloaded function items.""" - __slots__ = ('arguments', # Note that can be None if deserialized (type is a lie!) + __slots__ = ('arguments', # Note that items can be None if deserialized (type is a lie!) 'arg_names', # Names of arguments 'arg_kinds', # Kinds of arguments 'min_args', # Minimum number of arguments @@ -657,7 +657,7 @@ class FuncItem(FuncBase): 'expanded', # Variants of function with type variables with values expanded ) - __deletable__ = ('arguments', 'max_pos', 'min_args') + __deletable__ = ('max_pos', 'min_args') def __init__(self, arguments: List[Argument], @@ -770,8 +770,10 @@ def deserialize(cls, data: JsonDict) -> 'FuncDef': # NOTE: ret.info is set in the fixup phase. ret.arg_names = data['arg_names'] ret.arg_kinds = [ArgKind(x) for x in data['arg_kinds']] + ret.arguments = [] + for argname, argkind in zip(ret.arg_names, ret.arg_kinds): + ret.arguments += [Argument(Var(argname or ""), None, None, argkind)] # Leave these uninitialized so that future uses will trigger an error - del ret.arguments del ret.max_pos del ret.min_args return ret diff --git a/mypy/types.py b/mypy/types.py index dadbb84fe1c8..2c0044cbb4e7 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -1236,7 +1236,7 @@ def __init__(self, self.def_extras = { 'first_arg': ( definition.arguments[0].variable.name - if (getattr(definition, 'arguments', None) + if (definition.arguments and definition.arg_names and definition.info and not definition.is_static)