From 8c7b0f3fb745aa7bd0afedfbeb862eecc5fdff0c Mon Sep 17 00:00:00 2001 From: da-woods Date: Fri, 1 Oct 2021 10:29:34 +0100 Subject: Handle function "outer_attrs" more consistently (GH-4375) A few children of function nodes need to be consistently evaluated outside the function scope. This PR attempts to do so and thus fixes https://github.com/cython/cython/issues/4367. --- Cython/Compiler/Nodes.py | 2 ++ Cython/Compiler/ParseTreeTransforms.py | 2 -- Cython/Compiler/Visitor.py | 4 +++- tests/run/decorators.pyx | 20 ++++++++++++++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 4b0da59cf..9765b4cb2 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -1750,6 +1750,8 @@ class FuncDefNode(StatNode, BlockNode): code_object = None return_type_annotation = None + outer_attrs = None # overridden by some derived classes - to be visited outside the node's scope + def analyse_default_values(self, env): default_seen = 0 for arg in self.args: diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 0eb91163a..d6ef3fdfc 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -2054,8 +2054,6 @@ if VALUE is not None: def visit_DefNode(self, node): node = self.visit_FuncDefNode(node) env = self.current_env() - if isinstance(node, Nodes.DefNode) and node.is_wrapper: - env = env.parent_scope if (not isinstance(node, Nodes.DefNode) or node.fused_py_func or node.is_generator_body or not node.needs_assignment_synthesis(env)): diff --git a/Cython/Compiler/Visitor.py b/Cython/Compiler/Visitor.py index 5d35c8aac..3181ed448 100644 --- a/Cython/Compiler/Visitor.py +++ b/Cython/Compiler/Visitor.py @@ -370,8 +370,10 @@ class EnvTransform(CythonTransform): self.env_stack.pop() def visit_FuncDefNode(self, node): + outer_attrs = node.outer_attrs + self.visitchildren(node, attrs=outer_attrs) self.enter_scope(node, node.local_scope) - self._process_children(node) + self.visitchildren(node, attrs=None, exclude=outer_attrs) self.exit_scope() return node diff --git a/tests/run/decorators.pyx b/tests/run/decorators.pyx index 85834eb8b..54623e0cb 100644 --- a/tests/run/decorators.pyx +++ b/tests/run/decorators.pyx @@ -61,3 +61,23 @@ a = A() @a.decorate def i(x): return x - 1 + +def append_to_list_decorator(lst): + def do_append_to_list_dec(func): + def new_func(): + return lst + func() + return new_func + return do_append_to_list_dec + +def outer(arg1, arg2): + """ + ensure decorators are analysed in the correct scope + https://github.com/cython/cython/issues/4367 + mainly intended as a compile-time test (but it does run...) + >>> outer(append_to_list_decorator, [1,2,3]) + [1, 2, 3, 4] + """ + @arg1([x for x in arg2]) + def method(): + return [4] + return method() -- cgit v1.2.1