From 6023129e06b73e39a94d8cc646149f45e8e96038 Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Mon, 22 Oct 2018 17:01:48 -0700 Subject: [PATCH] Try #2, with less FuncDef --- mypy/nodes.py | 15 +++++++-------- mypy/plugin.py | 4 ---- mypy/plugins/common.py | 3 +-- mypy/semanal.py | 4 ---- mypy/server/aststrip.py | 24 ++++++++++-------------- mypy/server/update.py | 18 +++++++++--------- test-data/unit/fine-grained.test | 26 +++++++++++++++++++++++++- 7 files changed, 52 insertions(+), 42 deletions(-) diff --git a/mypy/nodes.py b/mypy/nodes.py index 416bb92cc12a..e7d14dafb850 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -379,7 +379,7 @@ def __str__(self) -> str: FUNCBASE_FLAGS = [ - 'is_property', 'is_class', 'is_static', 'is_final', 'plugin_generated' + 'is_property', 'is_class', 'is_static', 'is_final' ] # type: Final @@ -394,7 +394,6 @@ class FuncBase(Node): 'is_static', # Uses "@staticmethod" 'is_final', # Uses "@final" '_fullname', - 'plugin_generated', ) def __init__(self) -> None: @@ -411,7 +410,6 @@ def __init__(self) -> None: self.is_class = False self.is_static = False self.is_final = False - self.plugin_generated = False # Name with module prefix # TODO: Type should be Optional[str] self._fullname = cast(Bogus[str], None) @@ -2703,6 +2701,7 @@ class SymbolTableNode: 'module_hidden', 'cross_ref', 'implicit', + 'plugin_generated', 'no_serialize', ) @@ -2721,7 +2720,7 @@ def __init__(self, self.implicit = implicit self.module_hidden = module_hidden self.cross_ref = None # type: Optional[str] -# self.plugin_generated = plugin_generated + self.plugin_generated = plugin_generated self.no_serialize = no_serialize @property @@ -2778,8 +2777,8 @@ def serialize(self, prefix: str, name: str) -> JsonDict: data['module_public'] = False if self.implicit: data['implicit'] = True - # if self.plugin_generated: - # data['plugin_generated'] = True + if self.plugin_generated: + data['plugin_generated'] = True if self.kind == MODULE_REF: assert self.node is not None, "Missing module cross ref in %s for %s" % (prefix, name) data['cross_ref'] = self.node.fullname() @@ -2813,8 +2812,8 @@ def deserialize(cls, data: JsonDict) -> 'SymbolTableNode': stnode.module_public = data['module_public'] if 'implicit' in data: stnode.implicit = data['implicit'] - # if 'plugin_generated' in data: - # stnode.plugin_generated = data['plugin_generated'] + if 'plugin_generated' in data: + stnode.plugin_generated = data['plugin_generated'] return stnode diff --git a/mypy/plugin.py b/mypy/plugin.py index c5e4c497cb0b..ae910e766023 100644 --- a/mypy/plugin.py +++ b/mypy/plugin.py @@ -113,10 +113,6 @@ def lookup_qualified(self, name: str, ctx: Context, suppress_errors: bool = False) -> Optional[SymbolTableNode]: raise NotImplementedError - @abstractmethod - def add_symbol_to_type(self, info: TypeInfo, name: str, node: SymbolTableNode) -> None: - raise NotImplementedError - # A context for a function hook that infers the return type of a function with # a special signature. diff --git a/mypy/plugins/common.py b/mypy/plugins/common.py index ff1fe4b850d6..4c8b6530300c 100644 --- a/mypy/plugins/common.py +++ b/mypy/plugins/common.py @@ -109,7 +109,6 @@ def _add_method( func.type = set_callable_name(signature, func) func._fullname = info.fullname() + '.' + name func.line = info.line - func.plugin_generated = True - info.names[name] = SymbolTableNode(MDEF, func) + info.names[name] = SymbolTableNode(MDEF, func, plugin_generated=True) info.defn.defs.body.append(func) diff --git a/mypy/semanal.py b/mypy/semanal.py index a251b333e072..e94f0a56282c 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -3375,9 +3375,6 @@ def create_getattr_var(self, getattr_defn: SymbolTableNode, return SymbolTableNode(GDEF, v) return None - def add_symbol_to_type(self, info: TypeInfo, name: str, node: SymbolTableNode) -> None: - pass - def rebind_symbol_table_node(self, n: SymbolTableNode) -> Optional[SymbolTableNode]: """If node refers to old version of module, return reference to new version. @@ -3570,7 +3567,6 @@ def name_already_defined(self, name: str, ctx: Context, node = original_ctx.node elif isinstance(original_ctx, SymbolNode): node = original_ctx -# import pdb; pdb.set_trace() if isinstance(original_ctx, SymbolTableNode) and original_ctx.kind == MODULE_REF: # Since this is an import, original_ctx.node points to the module definition. diff --git a/mypy/server/aststrip.py b/mypy/server/aststrip.py index fc5bc63ddf66..1bc405a9d0bd 100644 --- a/mypy/server/aststrip.py +++ b/mypy/server/aststrip.py @@ -38,13 +38,13 @@ """ import contextlib -from typing import Union, Iterator, Optional +from typing import Union, Iterator, Optional, List from mypy.nodes import ( Node, FuncDef, NameExpr, MemberExpr, RefExpr, MypyFile, FuncItem, ClassDef, AssignmentStmt, ImportFrom, Import, TypeInfo, SymbolTable, Var, CallExpr, Decorator, OverloadedFuncDef, SuperExpr, UNBOUND_IMPORTED, GDEF, MDEF, IndexExpr, SymbolTableNode, ImportAll, TupleExpr, - ListExpr, ForStmt, Block, FuncBase, + ListExpr, ForStmt, Block, SymbolNode, FuncBase, ) from mypy.semanal_shared import create_indirect_imported_name from mypy.traverser import TraverserVisitor @@ -90,21 +90,17 @@ def visit_block(self, b: Block) -> None: def visit_class_def(self, node: ClassDef) -> None: """Strip class body and type info, but don't strip methods.""" - self.strip_type_info(node.info) + to_delete = set(self.strip_type_info(node.info)) node.type_vars = [] node.base_type_exprs.extend(node.removed_base_type_exprs) node.removed_base_type_exprs = [] - print(node.defs.body) node.defs.body = [s for s in node.defs.body - if not (isinstance(s, FuncBase) and s.plugin_generated)] - print(node.defs.body) + if s not in to_delete] with self.enter_class(node.info): super().visit_class_def(node) - def strip_type_info(self, info: TypeInfo) -> None: - print("stripping", info.fullname()) - + def strip_type_info(self, info: TypeInfo) -> List[SymbolNode]: info.type_vars = [] info.bases = [] info.is_abstract = False @@ -118,12 +114,12 @@ def strip_type_info(self, info: TypeInfo) -> None: info.declared_metaclass = None info.metaclass_type = None - to_delete = [k for k, v in info.names.items() - if isinstance(v.node, FuncBase) and v.node.plugin_generated] -# print("YO HOW BOUT THIS", to_delete, info.names.items()) - for k in to_delete: + # We need to delete any entries that were generated by plugins, + # since they will get regenerated. + to_delete = [(k, v) for k, v in info.names.items() if v.plugin_generated] + for k, _ in to_delete: del info.names[k] -# import pdb; pdb.set_trace() + return [v.node for k, v in to_delete if v.node] def visit_func_def(self, node: FuncDef) -> None: if not self.recurse_into_functions: diff --git a/mypy/server/update.py b/mypy/server/update.py index 74dbfcfdfd23..c1c688d71f54 100644 --- a/mypy/server/update.py +++ b/mypy/server/update.py @@ -846,12 +846,6 @@ def reprocess_nodes(manager: BuildManager, module_id) return set() - nodeset_ = set(s for s in nodeset - if not (isinstance(s.node, FuncBase) and s.node.plugin_generated)) - print(nodeset_ - nodeset) - nodeset = nodeset_ - print(nodeset) - file_node = manager.modules[module_id] old_symbols = find_symbol_tables_recursive(file_node.fullname(), file_node.names) old_symbols = {name: names.copy() for name, names in old_symbols.items()} @@ -891,7 +885,6 @@ def key(node: FineGrainedDeferredNode) -> int: fnam=file_node.path, options=options, active_type=deferred.active_typeinfo): -# import pdb; pdb.set_trace() manager.semantic_analyzer.refresh_partial(deferred.node, patches) # Third pass of semantic analysis. @@ -985,7 +978,9 @@ def update_deps(module_id: str, def lookup_target(manager: BuildManager, - target: str) -> Tuple[List[FineGrainedDeferredNode], Optional[TypeInfo]]: + target: str, + promote_generated: bool = True, + ) -> Tuple[List[FineGrainedDeferredNode], Optional[TypeInfo]]: """Look up a target by fully-qualified name. The first item in the return tuple is a list of deferred nodes that @@ -1020,6 +1015,11 @@ def not_found() -> None: or c not in node.names): not_found() # Stale dependency return [], None + if node.names[c].plugin_generated: + if not promote_generated: + return [], None + target = node.fullname() + break node = node.names[c].node if isinstance(node, TypeInfo): # A ClassDef target covers the body of the class and everything defined @@ -1040,7 +1040,7 @@ def not_found() -> None: for name, symnode in node.names.items(): node = symnode.node if isinstance(node, FuncDef): - method, _ = lookup_target(manager, target + '.' + name) + method, _ = lookup_target(manager, target + '.' + name, promote_generated=False) result.extend(method) return result, stale_info if isinstance(node, Decorator): diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test index dee939d8d06b..db892523c3aa 100644 --- a/test-data/unit/fine-grained.test +++ b/test-data/unit/fine-grained.test @@ -691,8 +691,32 @@ B(1, 2) b.py:8: error: Argument 1 to "B" has incompatible type "int"; expected "str" [builtins fixtures/list.pyi] +[case testDataclassUpdate3] +# flags: --python-version 3.6 +from b import B +B(1, 2) +[file b.py] +from a import A +from dataclasses import dataclass +@dataclass +class B(A): + b: int +[file a.py] +from dataclasses import dataclass +@dataclass +class A: + a: int - +[file a.py.2] +from dataclasses import dataclass +@dataclass +class A: + a: int + other: int +[builtins fixtures/list.pyi] +[out] +== +main:3: error: Too few arguments for "B" [case testAddBaseClassMethodCausingInvalidOverride] import m