Skip to content

Commit ffde4cd

Browse files
[3.12] gh-98442: fix locations of with statement's cleanup instructions (GH-120763) (#120787)
gh-98442: fix locations of with statement's cleanup instructions (GH-120763) (cherry picked from commit 55596ae) gh-98442: fix location of with statement's cleanup instructions Co-authored-by: Irit Katriel <[email protected]>
1 parent b2a7d71 commit ffde4cd

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

Lib/test/test_compile.py

+33
Original file line numberDiff line numberDiff line change
@@ -1856,6 +1856,39 @@ def test_lambda_return_position(self):
18561856
self.assertGreaterEqual(end_col, start_col)
18571857
self.assertLessEqual(end_col, code_end)
18581858

1859+
def test_return_in_with_positions(self):
1860+
# See gh-98442
1861+
def f():
1862+
with xyz:
1863+
1
1864+
2
1865+
3
1866+
4
1867+
return R
1868+
1869+
# All instructions should have locations on a single line
1870+
for instr in dis.get_instructions(f):
1871+
start_line, end_line, _, _ = instr.positions
1872+
self.assertEqual(start_line, end_line)
1873+
1874+
# Expect three load None instructions for the no-exception __exit__ call,
1875+
# and one RETURN_VALUE.
1876+
# They should all have the locations of the context manager ('xyz').
1877+
1878+
load_none = [instr for instr in dis.get_instructions(f) if
1879+
instr.opname == 'LOAD_CONST' and instr.argval is None]
1880+
return_value = [instr for instr in dis.get_instructions(f) if
1881+
instr.opname == 'RETURN_VALUE']
1882+
1883+
self.assertEqual(len(load_none), 3)
1884+
self.assertEqual(len(return_value), 1)
1885+
for instr in load_none + return_value:
1886+
start_line, end_line, start_col, end_col = instr.positions
1887+
self.assertEqual(start_line, f.__code__.co_firstlineno + 1)
1888+
self.assertEqual(end_line, f.__code__.co_firstlineno + 1)
1889+
self.assertEqual(start_col, 17)
1890+
self.assertEqual(end_col, 20)
1891+
18591892

18601893
class TestExpressionStackSize(unittest.TestCase):
18611894
# These tests check that the computed stack size for a code object
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix too wide source locations of the cleanup instructions of a with
2+
statement.

Python/compile.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END,
135135
struct fblockinfo {
136136
enum fblocktype fb_type;
137137
jump_target_label fb_block;
138+
location fb_loc;
138139
/* (optional) type-specific exit or cleanup block */
139140
jump_target_label fb_exit;
140141
/* (optional) additional information required for unwinding */
@@ -1467,6 +1468,7 @@ compiler_push_fblock(struct compiler *c, location loc,
14671468
f = &c->u->u_fblock[c->u->u_nfblocks++];
14681469
f->fb_type = t;
14691470
f->fb_block = block_label;
1471+
f->fb_loc = loc;
14701472
f->fb_exit = exit;
14711473
f->fb_datum = datum;
14721474
return SUCCESS;
@@ -1594,7 +1596,7 @@ compiler_unwind_fblock(struct compiler *c, location *ploc,
15941596

15951597
case WITH:
15961598
case ASYNC_WITH:
1597-
*ploc = LOC((stmt_ty)info->fb_datum);
1599+
*ploc = info->fb_loc;
15981600
ADDOP(c, *ploc, POP_BLOCK);
15991601
if (preserve_tos) {
16001602
ADDOP_I(c, *ploc, SWAP, 2);

0 commit comments

Comments
 (0)