Commit 09c4d9a3 authored by Mark Florisson's avatar Mark Florisson

Debugger: Fix accessing cell variables in outer scopes

parent f4166d52
......@@ -1760,10 +1760,14 @@ class DebugTransform(CythonTransform):
qname = '%s.%s.%s' % (entry.scope.outer_scope.qualified_name,
entry.scope.name,
entry.name)
elif entry.in_closure:
cname = '%s->%s' % (Naming.cur_scope_cname,
entry.cname)
qname = entry.qualified_name
else:
cname = entry.cname
qname = entry.qualified_name
if not entry.pos:
# this happens for variables that are not in the user's code,
# e.g. for the global __builtins__, __doc__, etc. We can just
......
......@@ -32,23 +32,16 @@ cdef class SomeClass(object):
def spam(self):
pass
def closure():
a = 1
def outer():
cdef object a = "an object"
def inner():
b = 2
# access closed over variables
print a, b
return inner
def closure_without_closing_variables():
a = 1
def inner2():
b = 2
print b
return inner2
closure()()
closure_without_closing_variables()()
outer()()
spam()
print "bye!"
\ No newline at end of file
......@@ -182,6 +182,7 @@ class TestKilled(DebugTestCase):
output = gdb.execute('cy run', to_string=True)
assert 'abort' in output.lower()
class DebugStepperTestCase(DebugTestCase):
def step(self, varnames_and_values, source_line=None, lineno=None):
......@@ -377,19 +378,30 @@ class TestExec(DebugTestCase):
class TestClosure(DebugTestCase):
def test_cython_closure(self):
self.break_and_run('def inner():')
def break_and_run_func(self, funcname):
gdb.execute('cy break ' + funcname)
gdb.execute('cy run')
def test_inner(self):
self.break_and_run_func('inner')
# Allow the Cython-generated code to initialize the scope variable
gdb.execute('cy step')
self.assertEqual(str(self.read_var('a')), '1')
self.assertEqual(str(self.read_var('a')), "'an object'")
print_result = gdb.execute('cy print a', to_string=True).strip()
self.assertEqual(print_result, 'a = 1')
self.assertEqual(print_result, "a = 'an object'")
def test_cython_closure_no_closing_variables(self):
self.break_and_run('def inner2():')
self.assertEqual(gdb.execute('cy locals', to_string=True), '')
def test_outer(self):
self.break_and_run_func('outer')
# Initialize scope with 'a' uninitialized
gdb.execute('cy step')
# Initialize 'a' to 1
gdb.execute('cy step')
print_result = gdb.execute('cy print a', to_string=True).strip()
self.assertEqual(print_result, "a = 'an object'")
_do_debug = os.environ.get('GDB_DEBUG')
......
......@@ -389,10 +389,20 @@ class CythonBase(object):
value)
def is_initialized(self, cython_func, local_name):
islocal = local_name in cython_func.locals
if islocal:
cyvar = cython_func.locals[local_name]
if '->' in cyvar.cname:
# Closed over free variable
try:
gdb.parse_and_eval(cyvar.cname)
return True
except RuntimeError:
return False
cur_lineno = self.get_cython_lineno()
return (local_name in cython_func.arguments or
(local_name in cython_func.locals and
cur_lineno > cython_func.locals[local_name].lineno))
(islocal and cur_lineno > cyvar.lineno))
class SourceFileDescriptor(object):
def __init__(self, filename, lexer, formatter=None):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment