cpython
cpython copied to clipboard
Source location of match sub-expressions are incorrect
def f(x):
match x:
case a,b:
return 1
import dis
from pprint import pprint as pp
def pos(p):
return (p.lineno, p.end_lineno, p.col_offset, p.end_col_offset)
pp([(pos(x.positions), x.opname, x.argval) for x in dis.get_instructions(f)])
Output is:
[((2, 2, 0, 0), 'RESUME', 0),
((3, 3, 8, 9), 'LOAD_FAST', 'x'),
((4, 4, 9, 12), 'MATCH_SEQUENCE', None),
((4, 4, 9, 12), 'POP_JUMP_IF_FALSE', 32),
((4, 4, 9, 12), 'GET_LEN', None),
((4, 4, 9, 12), 'LOAD_CONST', 2),
((4, 4, 9, 12), 'COMPARE_OP', '=='),
((4, 4, 9, 12), 'POP_JUMP_IF_FALSE', 32),
((4, 4, 9, 12), 'UNPACK_SEQUENCE', 2),
((4, 4, 11, 12), 'STORE_FAST', 'a'), <-- incorrect
((4, 4, 11, 12), 'STORE_FAST', 'b'),
((5, 5, 15, 16), 'LOAD_CONST', 1),
((5, 5, 15, 16), 'RETURN_VALUE', None),
((4, 4, 9, 12), 'POP_TOP', None),
((4, 4, 9, 12), 'LOAD_CONST', None),
((4, 4, 9, 12), 'RETURN_VALUE', None)]
- PR: gh-98775
FYI @nedbat .
The issue with name stores is pretty tricky, and stems from the fact that names are only bound once the entire pattern has matched. Fixing the locations for name stores in "normal" patterns won't be too hard (just keep the original node nearby and use that location for the final store).
However, or-patterns pose a challenge. For example, what should the location be when storing a and b?
match ...:
case [True, a, b] | [False, b, a]:
...
There's only one store instruction for each (at the very end), so I still think "the whole pattern" makes sense.