diff --git a/Lib/dis.py b/Lib/dis.py index d9936ce1a002c3..592419576f157a 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -413,6 +413,9 @@ def _get_instructions_bytes(code, varname_from_oparg=None, labels.add(target) starts_line = None for offset, op, arg in _unpack_opargs(code): + # get the next position before we skip a CACHE instruction + # to associate the correct position information. + positions = Positions(*next(co_positions, ())) if not show_caches and op == CACHE: continue if linestarts is not None: @@ -422,7 +425,6 @@ def _get_instructions_bytes(code, varname_from_oparg=None, is_jump_target = offset in labels argval = None argrepr = '' - positions = Positions(*next(co_positions, ())) if arg is not None: # Set argval to the dereferenced value of the argument when # available, and argrepr to the string representation of argval. diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 2f78d42cc724a6..700e8ad36ea27c 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1618,5 +1618,23 @@ def get_disassembly(self, tb): return output.getvalue() +class TestShowCaches(unittest.TestCase): + def test_show_caches(self): + def example_code(): + # this code is never executed + a.b.c(1 * x) + if x: + c = 5 + + def get_instructions(show_caches): + return [ + instr + for instr in dis.Bytecode(example_code, show_caches=show_caches) + if instr.opname != "CACHE" + ] + + self.assertEqual(get_instructions(True), get_instructions(False)) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2022-04-07-23-31-50.bpo-47233.JMopUw.rst b/Misc/NEWS.d/next/Library/2022-04-07-23-31-50.bpo-47233.JMopUw.rst new file mode 100644 index 00000000000000..f450d89befa006 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-04-07-23-31-50.bpo-47233.JMopUw.rst @@ -0,0 +1,2 @@ +Fix an issue where the default argument ``show_caches=False`` in :mod:`dis` +utilities could result in incorrect position information.