Skip to content

Commit 5a6cc3c

Browse files
authored
[3.12] gh-93691: fix too broad source locations of for statement iterators (GH-120330 (#120405)
[3.12] gh-93691: fix too broad source locations of for statement iterators (GH-120330). (cherry picked from commit 97b69db)
1 parent 8952323 commit 5a6cc3c

File tree

6 files changed

+63
-8
lines changed

6 files changed

+63
-8
lines changed

Lib/test/test_compiler_codegen.py

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def test_for_loop(self):
3939
('GET_ITER', None, 1),
4040
loop_lbl := self.Label(),
4141
('FOR_ITER', exit_lbl := self.Label(), 1),
42+
('NOP', None, 1, 1),
4243
('STORE_NAME', 1, 1),
4344
('PUSH_NULL', None, 2),
4445
('LOAD_NAME', 2, 2),

Lib/test/test_iter.py

+46
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import functools
1111
import contextlib
1212
import builtins
13+
import traceback
1314

1415
# Test result of triple loop (too big to inline)
1516
TRIPLETS = [(0, 0, 0), (0, 0, 1), (0, 0, 2),
@@ -1143,6 +1144,51 @@ def test_error_iter(self):
11431144
self.assertRaises(TypeError, iter, typ())
11441145
self.assertRaises(ZeroDivisionError, iter, BadIterableClass())
11451146

1147+
def test_exception_locations(self):
1148+
# The location of an exception raised from __init__ or
1149+
# __next__ should should be the iterator expression
1150+
1151+
class Iter:
1152+
def __init__(self, init_raises=False, next_raises=False):
1153+
if init_raises:
1154+
1/0
1155+
self.next_raises = next_raises
1156+
1157+
def __next__(self):
1158+
if self.next_raises:
1159+
1/0
1160+
1161+
def __iter__(self):
1162+
return self
1163+
1164+
def init_raises():
1165+
try:
1166+
for x in Iter(init_raises=True):
1167+
pass
1168+
except Exception as e:
1169+
return e
1170+
1171+
def next_raises():
1172+
try:
1173+
for x in Iter(next_raises=True):
1174+
pass
1175+
except Exception as e:
1176+
return e
1177+
1178+
for func, expected in [(init_raises, "Iter(init_raises=True)"),
1179+
(next_raises, "Iter(next_raises=True)"),
1180+
]:
1181+
with self.subTest(func):
1182+
exc = func()
1183+
f = traceback.extract_tb(exc.__traceback__)[0]
1184+
indent = 16
1185+
co = func.__code__
1186+
self.assertEqual(f.lineno, co.co_firstlineno + 2)
1187+
self.assertEqual(f.end_lineno, co.co_firstlineno + 2)
1188+
self.assertEqual(f.line[f.colno - indent : f.end_colno - indent],
1189+
expected)
1190+
1191+
11461192

11471193
if __name__ == "__main__":
11481194
unittest.main()

Lib/test/test_sys_settrace.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1634,15 +1634,15 @@ def func():
16341634
EXPECTED_EVENTS = [
16351635
(0, 'call'),
16361636
(2, 'line'),
1637-
(1, 'line'),
16381637
(-3, 'call'),
16391638
(-2, 'line'),
16401639
(-2, 'return'),
1641-
(4, 'line'),
16421640
(1, 'line'),
1641+
(4, 'line'),
1642+
(2, 'line'),
16431643
(-2, 'call'),
16441644
(-2, 'return'),
1645-
(1, 'return'),
1645+
(2, 'return'),
16461646
]
16471647

16481648
# C level events should be the same as expected and the same as Python level.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix source locations of instructions generated for the iterator of a for
2+
statement.

Programs/test_frozenmain.h

+4-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/compile.c

+7
Original file line numberDiff line numberDiff line change
@@ -3024,11 +3024,18 @@ compiler_for(struct compiler *c, stmt_ty s)
30243024
RETURN_IF_ERROR(compiler_push_fblock(c, loc, FOR_LOOP, start, end, NULL));
30253025

30263026
VISIT(c, expr, s->v.For.iter);
3027+
3028+
loc = LOC(s->v.For.iter);
30273029
ADDOP(c, loc, GET_ITER);
30283030

30293031
USE_LABEL(c, start);
30303032
ADDOP_JUMP(c, loc, FOR_ITER, cleanup);
30313033

3034+
/* Add NOP to ensure correct line tracing of multiline for statements.
3035+
* It will be removed later if redundant.
3036+
*/
3037+
ADDOP(c, LOC(s->v.For.target), NOP);
3038+
30323039
USE_LABEL(c, body);
30333040
VISIT(c, expr, s->v.For.target);
30343041
VISIT_SEQ(c, stmt, s->v.For.body);

0 commit comments

Comments
 (0)