From c0c8dd92f8dc485f518b08458f0e8963c3e76bad Mon Sep 17 00:00:00 2001 From: Mark Laws Date: Mon, 24 Oct 2016 02:07:02 +0900 Subject: [PATCH 1/5] Support conditional import in functions/classes --- mypy/semanal.py | 169 ++++++++++++++------- test-data/unit/check-unreachable-code.test | 15 +- 2 files changed, 132 insertions(+), 52 deletions(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 71d4dda12fe9..1d3398e982e5 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -2418,14 +2418,16 @@ def visit_await_expr(self, expr: AwaitExpr) -> None: # Helpers # - def lookup(self, name: str, ctx: Context) -> SymbolTableNode: + def lookup(self, name: str, ctx: Context, include_globals: bool = True, + report: bool = True) -> SymbolTableNode: """Look up an unqualified name in all active namespaces.""" # 1a. Name declared using 'global x' takes precedence if name in self.global_decls[-1]: if name in self.globals: return self.globals[name] else: - self.name_not_defined(name, ctx) + if report: + self.name_not_defined(name, ctx) return None # 1b. Name declared using 'nonlocal x' takes precedence if name in self.nonlocal_decls[-1]: @@ -2433,7 +2435,8 @@ def lookup(self, name: str, ctx: Context) -> SymbolTableNode: if table is not None and name in table: return table[name] else: - self.name_not_defined(name, ctx) + if report: + self.name_not_defined(name, ctx) return None # 2. Class attributes (if within class definition) if self.is_class_scope() and name in self.type.names: @@ -2442,22 +2445,25 @@ def lookup(self, name: str, ctx: Context) -> SymbolTableNode: for table in reversed(self.locals): if table is not None and name in table: return table[name] - # 4. Current file global scope - if name in self.globals: - return self.globals[name] - # 5. Builtins - b = self.globals.get('__builtins__', None) - if b: - table = cast(MypyFile, b.node).names - if name in table: - if name[0] == "_" and name[1] != "_": - self.name_not_defined(name, ctx) - return None - node = table[name] - return node + if include_globals: + # 4. Current file global scope + if name in self.globals: + return self.globals[name] + # 5. Builtins + b = self.globals.get('__builtins__', None) + if b: + table = cast(MypyFile, b.node).names + if name in table: + if name[0] == "_" and name[1] != "_": + if report: + self.name_not_defined(name, ctx) + return None + node = table[name] + return node # Give up. - self.name_not_defined(name, ctx) - self.check_for_obsolete_short_name(name, ctx) + if report: + self.name_not_defined(name, ctx) + self.check_for_obsolete_short_name(name, ctx) return None def check_for_obsolete_short_name(self, name: str, ctx: Context) -> None: @@ -2557,6 +2563,9 @@ def is_func_scope(self) -> bool: def is_class_scope(self) -> bool: return self.type is not None and not self.is_func_scope() + def is_module_scope(self) -> bool: + return not (self.is_class_scope() or self.is_func_scope()) + def add_symbol(self, name: str, node: SymbolTableNode, context: Context) -> None: if self.is_func_scope(): @@ -2739,14 +2748,16 @@ def visit_block(self, b: Block) -> None: self.sem.block_depth[-1] -= 1 def visit_assignment_stmt(self, s: AssignmentStmt) -> None: - for lval in s.lvalues: - self.analyze_lvalue(lval, explicit_type=s.type is not None) + if self.sem.is_module_scope(): + for lval in s.lvalues: + self.analyze_lvalue(lval, explicit_type=s.type is not None) def visit_func_def(self, func: FuncDef) -> None: sem = self.sem func.is_conditional = sem.block_depth[-1] > 0 func._fullname = sem.qualified_name(func.name()) - if func.name() in sem.globals: + at_module = sem.is_module_scope() + if at_module and func.name() in sem.globals: # Already defined in this module. original_sym = sem.globals[func.name()] if original_sym.kind == UNBOUND_IMPORTED: @@ -2761,25 +2772,50 @@ def visit_func_def(self, func: FuncDef) -> None: # Report error. sem.check_no_global(func.name(), func) else: - sem.globals[func.name()] = SymbolTableNode(GDEF, func, sem.cur_mod_id) + kind = self.kind_by_scope() + if kind == GDEF: + sem.globals[func.name()] = SymbolTableNode(kind, func, sem.cur_mod_id) + else: + ctx = sem.type_stack[-1] if kind == MDEF else sem.function_stack[-1] + if not sem.lookup(func.name(), ctx, include_globals=False, report=False): + sem.add_symbol(func.name(), SymbolTableNode(kind, func), ctx) + sem.function_stack.append(func) + sem.enter() + func.body.accept(self) + sem.leave() + sem.function_stack.pop() def visit_overloaded_func_def(self, func: OverloadedFuncDef) -> None: - self.sem.check_no_global(func.name(), func, True) + kind = self.kind_by_scope() + if kind == GDEF: + self.sem.check_no_global(func.name(), func, True) func._fullname = self.sem.qualified_name(func.name()) - self.sem.globals[func.name()] = SymbolTableNode(GDEF, func, - self.sem.cur_mod_id) + if kind == GDEF: + self.sem.globals[func.name()] = SymbolTableNode(kind, func, self.sem.cur_mod_id) + else: + ctx = self.sem.type_stack[-1] if kind == MDEF else self.sem.function_stack[-1] + self.sem.add_symbol(func.name(), SymbolTableNode(kind, func), ctx) def visit_class_def(self, cdef: ClassDef) -> None: - self.sem.check_no_global(cdef.name, cdef) + kind = self.kind_by_scope() + if kind == LDEF: + return + elif kind == GDEF: + self.sem.check_no_global(cdef.name, cdef) cdef.fullname = self.sem.qualified_name(cdef.name) info = TypeInfo(SymbolTable(), cdef, self.sem.cur_mod_id) info.set_line(cdef.line, cdef.column) cdef.info = info - self.sem.globals[cdef.name] = SymbolTableNode(GDEF, info, - self.sem.cur_mod_id) + if kind == GDEF: + self.sem.globals[cdef.name] = SymbolTableNode(kind, info, self.sem.cur_mod_id) + else: # MDEF + ctx = self.sem.type_stack[-1] + if not self.sem.lookup(cdef.name, ctx, include_globals=False, report=False): + self.sem.add_symbol(cdef.name, SymbolTableNode(kind, info), ctx) self.process_nested_classes(cdef) def process_nested_classes(self, outer_def: ClassDef) -> None: + self.sem.enter_class(outer_def) for node in outer_def.defs.body: if isinstance(node, ClassDef): node.info = TypeInfo(SymbolTable(), node, self.sem.cur_mod_id) @@ -2791,51 +2827,70 @@ def process_nested_classes(self, outer_def: ClassDef) -> None: symbol = SymbolTableNode(MDEF, node.info) outer_def.info.names[node.name] = symbol self.process_nested_classes(node) + elif isinstance(node, (ImportFrom, Import, ImportAll, IfStmt)): + node.accept(self) + self.sem.leave_class() def visit_import_from(self, node: ImportFrom) -> None: # We can't bind module names during the first pass, as the target module might be # unprocessed. However, we add dummy unbound imported names to the symbol table so # that we at least know that the name refers to a module. - node.is_top_level = True + node.is_top_level = self.sem.is_module_scope() + kind = self.kind_by_scope() for name, as_name in node.names: imported_name = as_name or name - if imported_name not in self.sem.globals: - self.sem.add_symbol(imported_name, SymbolTableNode(UNBOUND_IMPORTED, None), node) + if kind == GDEF: + if imported_name not in self.sem.globals: + self.sem.globals[imported_name] = SymbolTableNode(UNBOUND_IMPORTED, None) + else: + ctx = self.sem.type_stack[-1] if kind == MDEF else self.sem.function_stack[-1] + if not self.sem.lookup(imported_name, ctx, include_globals=False, report=False): + self.sem.add_symbol(imported_name, SymbolTableNode(UNBOUND_IMPORTED, None), + node) def visit_import(self, node: Import) -> None: - node.is_top_level = True + node.is_top_level = self.sem.is_module_scope() # This is similar to visit_import_from -- see the comment there. + kind = self.kind_by_scope() for id, as_id in node.ids: imported_id = as_id or id - if imported_id not in self.sem.globals: - self.sem.add_symbol(imported_id, SymbolTableNode(UNBOUND_IMPORTED, None), node) + if kind == GDEF: + if imported_id not in self.sem.globals: + self.sem.add_symbol(imported_id, SymbolTableNode(UNBOUND_IMPORTED, None), node) + else: + # If the previous symbol is a variable, this should take precedence. + self.sem.globals[imported_id] = SymbolTableNode(UNBOUND_IMPORTED, None) else: - # If the previous symbol is a variable, this should take precedence. - self.sem.globals[imported_id] = SymbolTableNode(UNBOUND_IMPORTED, None) + ctx = self.sem.type_stack[-1] if kind == MDEF else self.sem.function_stack[-1] + if not self.sem.lookup(imported_id, ctx, include_globals=False, report=False): + self.sem.add_symbol(imported_id, SymbolTableNode(UNBOUND_IMPORTED, None), node) def visit_import_all(self, node: ImportAll) -> None: - node.is_top_level = True + node.is_top_level = self.sem.is_module_scope() def visit_while_stmt(self, s: WhileStmt) -> None: - s.body.accept(self) - if s.else_body: - s.else_body.accept(self) + if self.sem.is_module_scope(): + s.body.accept(self) + if s.else_body: + s.else_body.accept(self) def visit_for_stmt(self, s: ForStmt) -> None: - self.analyze_lvalue(s.index) - s.body.accept(self) - if s.else_body: - s.else_body.accept(self) + if self.sem.is_module_scope(): + self.analyze_lvalue(s.index) + s.body.accept(self) + if s.else_body: + s.else_body.accept(self) def visit_with_stmt(self, s: WithStmt) -> None: - for n in s.target: - if n: - self.analyze_lvalue(n) - s.body.accept(self) + if self.sem.is_module_scope(): + for n in s.target: + if n: + self.analyze_lvalue(n) + s.body.accept(self) def visit_decorator(self, d: Decorator) -> None: d.var._fullname = self.sem.qualified_name(d.var.name()) - self.sem.add_symbol(d.var.name(), SymbolTableNode(GDEF, d.var), d) + self.sem.add_symbol(d.var.name(), SymbolTableNode(self.kind_by_scope(), d.var), d) def visit_if_stmt(self, s: IfStmt) -> None: infer_reachability_of_if_statement(s, pyversion=self.pyversion, platform=self.platform) @@ -2845,10 +2900,22 @@ def visit_if_stmt(self, s: IfStmt) -> None: s.else_body.accept(self) def visit_try_stmt(self, s: TryStmt) -> None: - self.sem.analyze_try_stmt(s, self, add_global=True) + if self.sem.is_module_scope(): + self.sem.analyze_try_stmt(s, self, add_global=self.sem.is_module_scope()) def analyze_lvalue(self, lvalue: Lvalue, explicit_type: bool = False) -> None: - self.sem.analyze_lvalue(lvalue, add_global=True, explicit_type=explicit_type) + self.sem.analyze_lvalue(lvalue, add_global=self.sem.is_module_scope(), + explicit_type=explicit_type) + + def kind_by_scope(self) -> int: + if self.sem.is_module_scope(): + return GDEF + elif self.sem.is_class_scope(): + return MDEF + elif self.sem.is_func_scope(): + return LDEF + else: + assert False, "Couldn't determine scope" class ThirdPass(TraverserVisitor): diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index d540a2db8beb..950e7df2aa14 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -372,7 +372,7 @@ def foo() -> None: [out] main: note: In function "foo": -[case testSysVersionInfoInMethod] +[case testSysPlatformInMethod] import sys class C: def foo(self) -> None: @@ -385,6 +385,19 @@ class C: [out] main: note: In member "foo" of class "C": +[case testSysPlatformInFunctionImport] +import sys +def foo() -> None: + if sys.platform != 'fictional': + import a + else: + import b as a + a.x +[file a.py] +x = 1 +[builtins fixtures/ops.pyi] +[out] + [case testCustomSysVersionInfo] # flags: --python-version 3.2 import sys From d43fbd215c4d4173aea1053c6106c5225725b423 Mon Sep 17 00:00:00 2001 From: Mark Laws Date: Mon, 24 Oct 2016 13:22:11 +0900 Subject: [PATCH 2/5] Suggested cleanups --- mypy/semanal.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 1d3398e982e5..0a948c8d5dd8 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -2419,14 +2419,19 @@ def visit_await_expr(self, expr: AwaitExpr) -> None: # def lookup(self, name: str, ctx: Context, include_globals: bool = True, - report: bool = True) -> SymbolTableNode: - """Look up an unqualified name in all active namespaces.""" + report_errors: bool = True) -> SymbolTableNode: + """Look up an unqualified name via standard scoping rules. + + If include_globals is explicitly False, the file-global scope will not + be searched. If report_errors is explicitly False, None will be + returned instead of reporting an error message on lookup failure. + """ # 1a. Name declared using 'global x' takes precedence if name in self.global_decls[-1]: if name in self.globals: return self.globals[name] else: - if report: + if report_errors: self.name_not_defined(name, ctx) return None # 1b. Name declared using 'nonlocal x' takes precedence @@ -2435,7 +2440,7 @@ def lookup(self, name: str, ctx: Context, include_globals: bool = True, if table is not None and name in table: return table[name] else: - if report: + if report_errors: self.name_not_defined(name, ctx) return None # 2. Class attributes (if within class definition) @@ -2455,13 +2460,13 @@ def lookup(self, name: str, ctx: Context, include_globals: bool = True, table = cast(MypyFile, b.node).names if name in table: if name[0] == "_" and name[1] != "_": - if report: + if report_errors: self.name_not_defined(name, ctx) return None node = table[name] return node # Give up. - if report: + if report_errors: self.name_not_defined(name, ctx) self.check_for_obsolete_short_name(name, ctx) return None @@ -2756,8 +2761,7 @@ def visit_func_def(self, func: FuncDef) -> None: sem = self.sem func.is_conditional = sem.block_depth[-1] > 0 func._fullname = sem.qualified_name(func.name()) - at_module = sem.is_module_scope() - if at_module and func.name() in sem.globals: + if sem.is_module_scope() and func.name() in sem.globals: # Already defined in this module. original_sym = sem.globals[func.name()] if original_sym.kind == UNBOUND_IMPORTED: @@ -2777,7 +2781,7 @@ def visit_func_def(self, func: FuncDef) -> None: sem.globals[func.name()] = SymbolTableNode(kind, func, sem.cur_mod_id) else: ctx = sem.type_stack[-1] if kind == MDEF else sem.function_stack[-1] - if not sem.lookup(func.name(), ctx, include_globals=False, report=False): + if not sem.lookup(func.name(), ctx, include_globals=False, report_errors=False): sem.add_symbol(func.name(), SymbolTableNode(kind, func), ctx) sem.function_stack.append(func) sem.enter() @@ -2810,7 +2814,7 @@ def visit_class_def(self, cdef: ClassDef) -> None: self.sem.globals[cdef.name] = SymbolTableNode(kind, info, self.sem.cur_mod_id) else: # MDEF ctx = self.sem.type_stack[-1] - if not self.sem.lookup(cdef.name, ctx, include_globals=False, report=False): + if not self.sem.lookup(cdef.name, ctx, include_globals=False, report_errors=False): self.sem.add_symbol(cdef.name, SymbolTableNode(kind, info), ctx) self.process_nested_classes(cdef) @@ -2844,7 +2848,8 @@ def visit_import_from(self, node: ImportFrom) -> None: self.sem.globals[imported_name] = SymbolTableNode(UNBOUND_IMPORTED, None) else: ctx = self.sem.type_stack[-1] if kind == MDEF else self.sem.function_stack[-1] - if not self.sem.lookup(imported_name, ctx, include_globals=False, report=False): + if not self.sem.lookup(imported_name, ctx, include_globals=False, + report_errors=False): self.sem.add_symbol(imported_name, SymbolTableNode(UNBOUND_IMPORTED, None), node) @@ -2862,7 +2867,8 @@ def visit_import(self, node: Import) -> None: self.sem.globals[imported_id] = SymbolTableNode(UNBOUND_IMPORTED, None) else: ctx = self.sem.type_stack[-1] if kind == MDEF else self.sem.function_stack[-1] - if not self.sem.lookup(imported_id, ctx, include_globals=False, report=False): + if not self.sem.lookup(imported_id, ctx, include_globals=False, + report_errors=False): self.sem.add_symbol(imported_id, SymbolTableNode(UNBOUND_IMPORTED, None), node) def visit_import_all(self, node: ImportAll) -> None: From c2ca2dbd3dc87b836b7b8475db9255e501ca480a Mon Sep 17 00:00:00 2001 From: Mark Laws Date: Mon, 24 Oct 2016 13:50:21 +0900 Subject: [PATCH 3/5] Simplify code --- mypy/semanal.py | 102 +++++++++++++++++------------------------------- 1 file changed, 35 insertions(+), 67 deletions(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 0a948c8d5dd8..17823bd58c4a 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -2418,21 +2418,14 @@ def visit_await_expr(self, expr: AwaitExpr) -> None: # Helpers # - def lookup(self, name: str, ctx: Context, include_globals: bool = True, - report_errors: bool = True) -> SymbolTableNode: - """Look up an unqualified name via standard scoping rules. - - If include_globals is explicitly False, the file-global scope will not - be searched. If report_errors is explicitly False, None will be - returned instead of reporting an error message on lookup failure. - """ + def lookup(self, name: str, ctx: Context) -> SymbolTableNode: + """Look up an unqualified name in all active namespaces.""" # 1a. Name declared using 'global x' takes precedence if name in self.global_decls[-1]: if name in self.globals: return self.globals[name] else: - if report_errors: - self.name_not_defined(name, ctx) + self.name_not_defined(name, ctx) return None # 1b. Name declared using 'nonlocal x' takes precedence if name in self.nonlocal_decls[-1]: @@ -2440,8 +2433,7 @@ def lookup(self, name: str, ctx: Context, include_globals: bool = True, if table is not None and name in table: return table[name] else: - if report_errors: - self.name_not_defined(name, ctx) + self.name_not_defined(name, ctx) return None # 2. Class attributes (if within class definition) if self.is_class_scope() and name in self.type.names: @@ -2450,25 +2442,22 @@ def lookup(self, name: str, ctx: Context, include_globals: bool = True, for table in reversed(self.locals): if table is not None and name in table: return table[name] - if include_globals: - # 4. Current file global scope - if name in self.globals: - return self.globals[name] - # 5. Builtins - b = self.globals.get('__builtins__', None) - if b: - table = cast(MypyFile, b.node).names - if name in table: - if name[0] == "_" and name[1] != "_": - if report_errors: - self.name_not_defined(name, ctx) - return None - node = table[name] - return node + # 4. Current file global scope + if name in self.globals: + return self.globals[name] + # 5. Builtins + b = self.globals.get('__builtins__', None) + if b: + table = cast(MypyFile, b.node).names + if name in table: + if name[0] == "_" and name[1] != "_": + self.name_not_defined(name, ctx) + return None + node = table[name] + return node # Give up. - if report_errors: - self.name_not_defined(name, ctx) - self.check_for_obsolete_short_name(name, ctx) + self.name_not_defined(name, ctx) + self.check_for_obsolete_short_name(name, ctx) return None def check_for_obsolete_short_name(self, name: str, ctx: Context) -> None: @@ -2761,7 +2750,8 @@ def visit_func_def(self, func: FuncDef) -> None: sem = self.sem func.is_conditional = sem.block_depth[-1] > 0 func._fullname = sem.qualified_name(func.name()) - if sem.is_module_scope() and func.name() in sem.globals: + at_module = sem.is_module_scope() + if at_module and func.name() in sem.globals: # Already defined in this module. original_sym = sem.globals[func.name()] if original_sym.kind == UNBOUND_IMPORTED: @@ -2776,13 +2766,8 @@ def visit_func_def(self, func: FuncDef) -> None: # Report error. sem.check_no_global(func.name(), func) else: - kind = self.kind_by_scope() - if kind == GDEF: - sem.globals[func.name()] = SymbolTableNode(kind, func, sem.cur_mod_id) - else: - ctx = sem.type_stack[-1] if kind == MDEF else sem.function_stack[-1] - if not sem.lookup(func.name(), ctx, include_globals=False, report_errors=False): - sem.add_symbol(func.name(), SymbolTableNode(kind, func), ctx) + if at_module: + sem.globals[func.name()] = SymbolTableNode(GDEF, func, sem.cur_mod_id) sem.function_stack.append(func) sem.enter() func.body.accept(self) @@ -2796,9 +2781,6 @@ def visit_overloaded_func_def(self, func: OverloadedFuncDef) -> None: func._fullname = self.sem.qualified_name(func.name()) if kind == GDEF: self.sem.globals[func.name()] = SymbolTableNode(kind, func, self.sem.cur_mod_id) - else: - ctx = self.sem.type_stack[-1] if kind == MDEF else self.sem.function_stack[-1] - self.sem.add_symbol(func.name(), SymbolTableNode(kind, func), ctx) def visit_class_def(self, cdef: ClassDef) -> None: kind = self.kind_by_scope() @@ -2812,10 +2794,6 @@ def visit_class_def(self, cdef: ClassDef) -> None: cdef.info = info if kind == GDEF: self.sem.globals[cdef.name] = SymbolTableNode(kind, info, self.sem.cur_mod_id) - else: # MDEF - ctx = self.sem.type_stack[-1] - if not self.sem.lookup(cdef.name, ctx, include_globals=False, report_errors=False): - self.sem.add_symbol(cdef.name, SymbolTableNode(kind, info), ctx) self.process_nested_classes(cdef) def process_nested_classes(self, outer_def: ClassDef) -> None: @@ -2839,37 +2817,27 @@ def visit_import_from(self, node: ImportFrom) -> None: # We can't bind module names during the first pass, as the target module might be # unprocessed. However, we add dummy unbound imported names to the symbol table so # that we at least know that the name refers to a module. - node.is_top_level = self.sem.is_module_scope() - kind = self.kind_by_scope() + at_module = self.sem.is_module_scope() + node.is_top_level = at_module + if not at_module: + return for name, as_name in node.names: imported_name = as_name or name - if kind == GDEF: - if imported_name not in self.sem.globals: - self.sem.globals[imported_name] = SymbolTableNode(UNBOUND_IMPORTED, None) - else: - ctx = self.sem.type_stack[-1] if kind == MDEF else self.sem.function_stack[-1] - if not self.sem.lookup(imported_name, ctx, include_globals=False, - report_errors=False): - self.sem.add_symbol(imported_name, SymbolTableNode(UNBOUND_IMPORTED, None), - node) + if imported_name not in self.sem.globals: + self.sem.add_symbol(imported_name, SymbolTableNode(UNBOUND_IMPORTED, None), node) def visit_import(self, node: Import) -> None: node.is_top_level = self.sem.is_module_scope() # This is similar to visit_import_from -- see the comment there. - kind = self.kind_by_scope() + if not self.sem.is_module_scope(): + return for id, as_id in node.ids: imported_id = as_id or id - if kind == GDEF: - if imported_id not in self.sem.globals: - self.sem.add_symbol(imported_id, SymbolTableNode(UNBOUND_IMPORTED, None), node) - else: - # If the previous symbol is a variable, this should take precedence. - self.sem.globals[imported_id] = SymbolTableNode(UNBOUND_IMPORTED, None) + if imported_id not in self.sem.globals: + self.sem.add_symbol(imported_id, SymbolTableNode(UNBOUND_IMPORTED, None), node) else: - ctx = self.sem.type_stack[-1] if kind == MDEF else self.sem.function_stack[-1] - if not self.sem.lookup(imported_id, ctx, include_globals=False, - report_errors=False): - self.sem.add_symbol(imported_id, SymbolTableNode(UNBOUND_IMPORTED, None), node) + # If the previous symbol is a variable, this should take precedence. + self.sem.globals[imported_id] = SymbolTableNode(UNBOUND_IMPORTED, None) def visit_import_all(self, node: ImportAll) -> None: node.is_top_level = self.sem.is_module_scope() From 09ecc92e51220475da0e8faa5a55d17c46e2850c Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 28 Oct 2016 11:18:07 -0700 Subject: [PATCH 4/5] Added a comment and call sem.errors.{push,pop}_function() --- mypy/semanal.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mypy/semanal.py b/mypy/semanal.py index 17823bd58c4a..5dda5c771820 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -2768,10 +2768,13 @@ def visit_func_def(self, func: FuncDef) -> None: else: if at_module: sem.globals[func.name()] = SymbolTableNode(GDEF, func, sem.cur_mod_id) + # Also analyze the function body (in case there are conditional imports). sem.function_stack.append(func) + sem.errors.push_function(defn.name()) sem.enter() func.body.accept(self) sem.leave() + sem.errors.pop_function() sem.function_stack.pop() def visit_overloaded_func_def(self, func: OverloadedFuncDef) -> None: From 8e45bab57eb57a4ef60bafca3c13206aff23e6b9 Mon Sep 17 00:00:00 2001 From: Mark Laws Date: Sat, 29 Oct 2016 04:16:24 +0900 Subject: [PATCH 5/5] Fix variable name --- mypy/semanal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 5dda5c771820..733bc6da8b28 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -2770,7 +2770,7 @@ def visit_func_def(self, func: FuncDef) -> None: sem.globals[func.name()] = SymbolTableNode(GDEF, func, sem.cur_mod_id) # Also analyze the function body (in case there are conditional imports). sem.function_stack.append(func) - sem.errors.push_function(defn.name()) + sem.errors.push_function(func.name()) sem.enter() func.body.accept(self) sem.leave()