line number for a return in a with block after 3.10 is that of the with, not the return statement · Issue #93975 · python/cpython (original) (raw)
def foo() -> int: with open('/dev/null') as devnull: return 'a'
In Python 3.10 onwards, the reported line number for the return
statement is incorrect.
Python main 3.12-main-ish not far from 3.11:
>>> def foo() -> int:
... with open('a') as f:
... return 'b'
...
>>> dis.dis(foo)
1 0 RESUME 0
2 2 LOAD_GLOBAL 1 (NULL + open)
14 LOAD_CONST 1 ('a')
16 CALL 1
26 BEFORE_WITH
28 STORE_FAST 0 (f)
3 30 NOP
2 32 LOAD_CONST 0 (None)
34 LOAD_CONST 0 (None)
36 LOAD_CONST 0 (None)
38 CALL 2
48 POP_TOP
50 LOAD_CONST 2 ('b')
52 RETURN_VALUE
>> 54 PUSH_EXC_INFO
56 WITH_EXCEPT_START
58 POP_JUMP_FORWARD_IF_TRUE 4 (to 68)
60 RERAISE 2
>> 62 COPY 3
64 POP_EXCEPT
66 RERAISE 1
>> 68 POP_TOP
70 POP_EXCEPT
72 POP_TOP
74 POP_TOP
76 LOAD_CONST 0 (None)
78 RETURN_VALUE
ExceptionTable:
28 to 30 -> 54 [1] lasti
54 to 60 -> 62 [3] lasti
68 to 68 -> 62 [3] lasti
>>> sys.version_info
sys.version_info(major=3, minor=12, micro=0, releaselevel='alpha', serial=0)
The only thing attributed to line 3 is a NOP. The RETURN_VALUE of 'b' is listed as line 2. That is wrong.
Python 3.9:
>>> def foo() -> int:
... with open('a') as f:
... return 'b'
...
>>> dis.dis(foo)
2 0 LOAD_GLOBAL 0 (open)
2 LOAD_CONST 1 ('a')
4 CALL_FUNCTION 1
6 SETUP_WITH 18 (to 26)
8 STORE_FAST 0 (f)
3 10 POP_BLOCK
12 LOAD_CONST 0 (None)
14 DUP_TOP
16 DUP_TOP
18 CALL_FUNCTION 3
20 POP_TOP
22 LOAD_CONST 2 ('b')
24 RETURN_VALUE
>> 26 WITH_EXCEPT_START
28 POP_JUMP_IF_TRUE 32
30 RERAISE
>> 32 POP_TOP
34 POP_TOP
36 POP_TOP
38 POP_EXCEPT
40 POP_TOP
42 LOAD_CONST 0 (None)
44 RETURN_VALUE
>>> sys.version_info
sys.version_info(major=3, minor=9, micro=12, releaselevel='final', serial=0)
Noticed by @martindemello working on a 3.10 error attribution bug in pytype.