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): ...@@ -1760,10 +1760,14 @@ class DebugTransform(CythonTransform):
qname = '%s.%s.%s' % (entry.scope.outer_scope.qualified_name, qname = '%s.%s.%s' % (entry.scope.outer_scope.qualified_name,
entry.scope.name, entry.scope.name,
entry.name) entry.name)
elif entry.in_closure:
cname = '%s->%s' % (Naming.cur_scope_cname,
entry.cname)
qname = entry.qualified_name
else: else:
cname = entry.cname cname = entry.cname
qname = entry.qualified_name qname = entry.qualified_name
if not entry.pos: if not entry.pos:
# this happens for variables that are not in the user's code, # this happens for variables that are not in the user's code,
# e.g. for the global __builtins__, __doc__, etc. We can just # e.g. for the global __builtins__, __doc__, etc. We can just
......
...@@ -32,23 +32,16 @@ cdef class SomeClass(object): ...@@ -32,23 +32,16 @@ cdef class SomeClass(object):
def spam(self): def spam(self):
pass pass
def closure(): def outer():
a = 1 cdef object a = "an object"
def inner(): def inner():
b = 2 b = 2
# access closed over variables # access closed over variables
print a, b print a, b
return inner return inner
def closure_without_closing_variables():
a = 1
def inner2():
b = 2
print b
return inner2
closure()() outer()()
closure_without_closing_variables()()
spam() spam()
print "bye!" print "bye!"
\ No newline at end of file
...@@ -182,6 +182,7 @@ class TestKilled(DebugTestCase): ...@@ -182,6 +182,7 @@ class TestKilled(DebugTestCase):
output = gdb.execute('cy run', to_string=True) output = gdb.execute('cy run', to_string=True)
assert 'abort' in output.lower() assert 'abort' in output.lower()
class DebugStepperTestCase(DebugTestCase): class DebugStepperTestCase(DebugTestCase):
def step(self, varnames_and_values, source_line=None, lineno=None): def step(self, varnames_and_values, source_line=None, lineno=None):
...@@ -377,19 +378,30 @@ class TestExec(DebugTestCase): ...@@ -377,19 +378,30 @@ class TestExec(DebugTestCase):
class TestClosure(DebugTestCase): class TestClosure(DebugTestCase):
def test_cython_closure(self): def break_and_run_func(self, funcname):
self.break_and_run('def inner():') 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 # Allow the Cython-generated code to initialize the scope variable
gdb.execute('cy step') 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() 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): def test_outer(self):
self.break_and_run('def inner2():') self.break_and_run_func('outer')
self.assertEqual(gdb.execute('cy locals', to_string=True), '')
# 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') _do_debug = os.environ.get('GDB_DEBUG')
......
...@@ -389,10 +389,20 @@ class CythonBase(object): ...@@ -389,10 +389,20 @@ class CythonBase(object):
value) value)
def is_initialized(self, cython_func, local_name): 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() cur_lineno = self.get_cython_lineno()
return (local_name in cython_func.arguments or return (local_name in cython_func.arguments or
(local_name in cython_func.locals and (islocal and cur_lineno > cyvar.lineno))
cur_lineno > cython_func.locals[local_name].lineno))
class SourceFileDescriptor(object): class SourceFileDescriptor(object):
def __init__(self, filename, lexer, formatter=None): 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