Closed
Description
We perform some manual fiddling with positions for attribute lookups at a few different points in the compiler. However, the extended position information for these locations can be nonsensical in some edge cases. Here is one (admittedly contrived) example:
>>> def foo():
... (bar.
... baz)
...
>>> for instruction in dis.get_instructions(foo):
... print(instruction.positions, instruction.opname)
...
Positions(lineno=1, end_lineno=1, col_offset=0, end_col_offset=0) RESUME
Positions(lineno=2, end_lineno=2, col_offset=5, end_col_offset=8) LOAD_GLOBAL
Positions(lineno=3, end_lineno=3, col_offset=5, end_col_offset=3) LOAD_ATTR
Positions(lineno=3, end_lineno=3, col_offset=5, end_col_offset=3) POP_TOP
Positions(lineno=3, end_lineno=3, col_offset=5, end_col_offset=3) LOAD_CONST
Positions(lineno=3, end_lineno=3, col_offset=5, end_col_offset=3) RETURN_VALUE
The last four instructions claim to be located on line 3, starting with at column 5 and ending at column 3 (which doesn't make sense).
A slight variation (using a method call) is even weirder:
>>> def foo():
... (bar.
... baz(
... ))
...
>>> for instruction in dis.get_instructions(foo):
... print(instruction.positions, instruction.opname)
...
Positions(lineno=1, end_lineno=1, col_offset=0, end_col_offset=0) RESUME
Positions(lineno=2, end_lineno=2, col_offset=5, end_col_offset=8) LOAD_GLOBAL
Positions(lineno=3, end_lineno=3, col_offset=None, end_col_offset=None) LOAD_ATTR
Positions(lineno=3, end_lineno=4, col_offset=None, end_col_offset=1) CALL
Positions(lineno=3, end_lineno=4, col_offset=None, end_col_offset=1) POP_TOP
Positions(lineno=3, end_lineno=4, col_offset=None, end_col_offset=1) LOAD_CONST
Positions(lineno=3, end_lineno=4, col_offset=None, end_col_offset=1) RETURN_VALUE
Here the col_offset
is totally nonexistent, even in cases where end_col_offset
is set! I suspect that this may be because the column math just happened to underflow the valid column range (>=0) and end up at -1
, which is a special value we use to mean "missing".