Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

line number for a return in a with block after 3.10 is that of the with, not the return statement #93975

Open
gpshead opened this issue Jun 18, 2022 · 1 comment
Assignees
Labels
3.10 3.11 3.12 interpreter-core type-bug

Comments

@gpshead
Copy link
Member

@gpshead gpshead commented Jun 18, 2022

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.

@gpshead gpshead added type-bug interpreter-core 3.11 3.10 3.12 labels Jun 18, 2022
@dignissimus
Copy link
Contributor

@dignissimus dignissimus commented Jun 18, 2022

The issue was introduced in 937cebc
See bpo-44298: #88464

The same behaviour occurs with try-finally blocks on both 3.9 and 3.10+

def function():
    try:
        return
    finally:
        pass

With the above code, disassembling on Python 3.10.5 produces the following

  1           0 LOAD_CONST               0 (<code object function at 0x7f96b4e0d000, file "a.py", line 1>)
              2 LOAD_CONST               1 ('function')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (function)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE

Disassembly of <code object function at 0x7f96b4e0d000, file "tryfinally.py", line 1>:
  2           0 SETUP_FINALLY            3 (to 8)

  3           2 POP_BLOCK

  5           4 LOAD_CONST               0 (None)
              6 RETURN_VALUE
        >>    8 RERAISE                  0

And on 3.9.0

  1           0 LOAD_CONST               0 (<code object function at 0x7f72158a8be0, file "/tmp/a.py", line 1>)
              2 LOAD_CONST               1 ('function')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (function)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE

Disassembly of <code object function at 0x7f72158a8be0, file "tryfinally.py", line 1>:
  2           0 SETUP_FINALLY            6 (to 8)

  3           2 POP_BLOCK
              4 LOAD_CONST               0 (None)
              6 RETURN_VALUE

  5     >>    8 RERAISE
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE

miss-islington pushed a commit that referenced this issue Jun 18, 2022
- gh-93957: Provide nicer error reporting from subprocesses in test_venv.EnsurePipTest.test_with_pip.
- Update changelog

This change does three things:

1. Extract a function for trapping output in subprocesses.
2. Emit both stdout and stderr when encountering an error.
3. Apply the change to `ensurepip._uninstall` check.
jaraco added a commit that referenced this issue Jun 19, 2022
- gh-93957: Provide nicer error reporting from subprocesses in test_venv.EnsurePipTest.test_with_pip.
- Update changelog

This change does three things:

1. Extract a function for trapping output in subprocesses.
2. Emit both stdout and stderr when encountering an error.
3. Apply the change to `ensurepip._uninstall` check.
(cherry picked from commit 6066f45)

Co-authored-by: Jason R. Coombs <jaraco@jaraco.com>
jaraco added a commit that referenced this issue Jun 19, 2022
- gh-93957: Provide nicer error reporting from subprocesses in test_venv.EnsurePipTest.test_with_pip.
- Update changelog

This change does three things:

1. Extract a function for trapping output in subprocesses.
2. Emit both stdout and stderr when encountering an error.
3. Apply the change to `ensurepip._uninstall` check..
(cherry picked from commit 6066f45)

Co-authored-by: Jason R. Coombs <jaraco@jaraco.com>
jaraco added a commit that referenced this issue Jun 19, 2022
- gh-93957: Provide nicer error reporting from subprocesses in test_venv.EnsurePipTest.test_with_pip.
- Update changelog

This change does three things:

1. Extract a function for trapping output in subprocesses.
2. Emit both stdout and stderr when encountering an error.
3. Apply the change to `ensurepip._uninstall` check..
(cherry picked from commit 6066f45)

Co-authored-by: Jason R. Coombs <jaraco@jaraco.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.10 3.11 3.12 interpreter-core type-bug
Projects
None yet
Development

No branches or pull requests

3 participants