8000 bpo-44446: set lineno in generator instructions · python/cpython@caba5a7 · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit caba5a7

Browse files
committed
bpo-44446: set lineno in generator instructions
When generator instructions were added to bytecode, lineno was always set to -1, instead of the line number. This patch sets the lineno, if there is one. Signed-off-by: Filipe Laíns <lains@riseup.net>
1 parent 7f01f77 commit caba5a7

File tree

4 files changed

+2696
-2678
lines changed

4 files changed

+2696
-2678
lines changed

Lib/test/test_frame.py

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -145,18 +145,27 @@ class C:
145145

146146
class FrameAttrsTest(unittest.TestCase):
147147

148-
def make_frames(self):
149-
def outer():
150-
x = 5
151-
y = 6
152-
def inner():
153-
z = x + 2
154-
1/0
155-
t = 9
156-
return inner()
148+
@staticmethod
149+
def outer():
150+
x = 5
151+
y = 6
152+
def inner():
153+
z = x + 2
154+
1/0
155+
t = 9
156+
return inner()
157+
158+
@staticmethod
159+
def generator():
160+
def foo():
161+
yield
162+
assert False
163+
list(foo())
164+
165+
def make_frames(self, func):
157166
try:
158-
outer()
159-
except ZeroDivisionError as e:
167+
func()
168+
except (ZeroDivisionError, AssertionError) as e:
160169
tb = e.__traceback__
161170
frames = []
162171
while tb:
@@ -165,7 +174,7 @@ def inner():
165174
return frames
166175

167176
def test_locals(self):
168-
f, outer, inner = self.make_frames()
177+
f, outer, inner = self.make_frames(self.outer)
169178
outer_locals = outer.f_locals
170179
self.assertIsInstance(outer_locals.pop('inner'), types.FunctionType)
171180
self.assertEqual(outer_locals, {'x': 5, 'y': 6})
@@ -174,15 +183,15 @@ def test_locals(self):
174183

175184
def test_clear_locals(self):
176185
# Test f_locals after clear() (issue #21897)
177-
f, outer, inner = self.make_frames()
186+
f, outer, inner = self.make_frames(self.outer)
178187
outer.clear()
179188
inner.clear()
180189
self.assertEqual(outer.f_locals, {})
181190
self.assertEqual(inner.f_locals, {})
182191

183192
def test_locals_clear_locals(self):
184193
# Test f_locals before and after clear() (to exercise caching)
185-
f, outer, inner = self.make_frames()
194+
f, outer, inner = self.make_frames(self.outer)
186195
outer.f_locals
187196
inner.f_locals
188197
outer.clear()
@@ -191,10 +200,14 @@ def test_locals_clear_locals(self):
191200
self.assertEqual(inner.f_locals, {})
192201

193202
def test_f_lineno_del_segfault(self):
194-
f, _, _ = self.make_frames()
203+
f, _, _ = self.make_frames(self.outer)
195204
with self.assertRaises(AttributeError):
196205
del f.f_lineno
197206

207+
def test_generator_lineno(self):
208+
f, _, generator = self.make_frames(self.generator)
209+
self.assertEqual(generator.f_lineno, generator.f_code.co_firstlineno + 2)
210+
198211

199212
class ReprTest(unittest.TestCase):
200213
"""
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Set ``lineno`` in generator instructions when generating bytecode.

Python/compile.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7434,6 +7434,11 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock,
74347434
return -1;
74357435
}
74367436

7437+
int lineno = -1;
7438+
if (entryblock->b_iused > 0) {
7439+
lineno = entryblock->b_instr[0].i_lineno;
7440+
}
7441+
74377442
/* Set up cells for any variable that escapes, to be put in a closure. */
74387443
const int ncellvars = (int)PyDict_GET_SIZE(c->u->u_cellvars);
74397444
if (ncellvars) {
@@ -7485,7 +7490,7 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock,
74857490
struct instr gen_start = {
74867491
.i_opcode = GEN_START,
74877492
.i_oparg = kind,
7488-
.i_lineno = -1,
7493+
.i_lineno = lineno,
74897494
.i_target = NULL,
74907495
};
74917496
if (insert_instruction(entryblock, 0, &gen_start) < 0) {

0 commit comments

Comments
 (0)
0