Skip to content

bpo-43754: Eliminate bindings for partial pattern matches #25229

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

Merged
merged 57 commits into from
May 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
f47a953
Replace ROT_* with ROTATE, use list for stores.
brandtbucher Mar 26, 2021
125e8e4
Get "as" assignments working with deferred stores.
brandtbucher Apr 1, 2021
dd8070a
Fix or-patterns.
brandtbucher Apr 1, 2021
6a602e0
Get or patterns working again.
brandtbucher Apr 2, 2021
96b73e1
Get basic mapping patterns working.
brandtbucher Apr 2, 2021
ef3c4b4
Get some sequences working.
brandtbucher Apr 2, 2021
c2c1007
Fix issue with name stores in subpatterns.
brandtbucher Apr 2, 2021
87472c0
Get everything except class patterns working.
brandtbucher Apr 2, 2021
2f4f301
Get class patterns working (all tests pass now)!
brandtbucher Apr 2, 2021
e9e9e7b
Successfully untangle names in alternatives.
brandtbucher Apr 2, 2021
24bc5ff
Catch up with master.
brandtbucher Apr 2, 2021
fa05706
Update benchmark command
brandtbucher Apr 2, 2021
3e29a0e
Remove old comment.
brandtbucher Apr 3, 2021
c5fd080
Add comments and handling for memory errors
brandtbucher Apr 3, 2021
d242af1
Get or patterns working again.
brandtbucher Apr 3, 2021
8c9d7cf
Don't use pop_on_fail anymore
brandtbucher Apr 3, 2021
6da075e
Change ROTATE implementation
brandtbucher Apr 3, 2021
28b72d0
Add the ROT_* opcodes back.
brandtbucher Apr 4, 2021
fa0068a
ROTATE -> ROT_N and ditch pc->pop_on_fail
brandtbucher Apr 4, 2021
28cd4d8
Fix bad find-and-replace
brandtbucher Apr 4, 2021
8664bd7
Add docs for ROT_N
brandtbucher Apr 4, 2021
f72dc87
Remove old comment
brandtbucher Apr 4, 2021
694bfb4
Lots of cleanup and comments
brandtbucher Apr 4, 2021
e4b4942
Add proper error handling to compiler_match
brandtbucher Apr 4, 2021
37c324d
More cleanup
brandtbucher Apr 4, 2021
85ee8c9
WIP on cleaning up name handling in alternatives
brandtbucher Apr 4, 2021
e6f234c
Clean up compiler_pattern_mapping
brandtbucher Apr 4, 2021
2facf77
Catch up with master
brandtbucher Apr 5, 2021
2c5c447
*Finally* figure out why -R runs weren't failing
brandtbucher Apr 5, 2021
465c176
Get nested alternatives working better
brandtbucher Apr 5, 2021
942c458
Improve efficiency of alternatives
brandtbucher Apr 5, 2021
e791f85
Ditch pc->adj
brandtbucher Apr 5, 2021
63ff507
Catch up with master
brandtbucher Apr 5, 2021
26b49d4
A bit of cleanup
brandtbucher Apr 5, 2021
df70e5a
Fold rotations when possible
brandtbucher Apr 6, 2021
8163549
Catch up with master
brandtbucher Apr 6, 2021
26ba113
More cleanup
brandtbucher Apr 6, 2021
db9a3b1
A bit more cleanup
brandtbucher Apr 6, 2021
bad089c
Catch up with master
brandtbucher Apr 6, 2021
766f130
Catch up with master
brandtbucher Apr 6, 2021
2c53ec5
Ditch pattern_helper_or
brandtbucher Apr 6, 2021
9255816
Move comment
brandtbucher Apr 6, 2021
169c6eb
Fix possible bad free
brandtbucher Apr 6, 2021
c0bc66e
Catch up with master
brandtbucher Apr 11, 2021
d22a8e8
Catch up with master
brandtbucher Apr 23, 2021
13bb083
ROT_* -> ROTATE
brandtbucher Apr 23, 2021
53cb874
cleanup_fail_pop always starts a new block
brandtbucher Apr 24, 2021
3a4f63e
Cleanup
brandtbucher Apr 24, 2021
88975f8
Clean up cleanup_fail_pop
brandtbucher Apr 24, 2021
8e25f26
blurb add
brandtbucher Apr 24, 2021
476bab4
"Resolve" nasty merge conflicts
brandtbucher Apr 30, 2021
8813dbb
Well that wasn't bad at all!
brandtbucher Apr 30, 2021
2beea3b
Clean up whitespace
brandtbucher Apr 30, 2021
3f81eff
Catch up with master
brandtbucher Apr 30, 2021
85084b1
ROTATE -> ROT_N and add back ROT_*
brandtbucher May 1, 2021
e818ff3
Fix whitespace
brandtbucher May 1, 2021
99f0ec6
Don't store names in reverse order
brandtbucher May 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Doc/library/dis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,15 @@ All of the following opcodes use their arguments.

.. versionadded:: 3.10


.. opcode:: ROT_N (count)

Lift the top *count* stack items one position up, and move TOS down to
position *count*.

.. versionadded:: 3.10


.. opcode:: HAVE_ARGUMENT

This is not really an opcode. It identifies the dividing line between
Expand Down
1 change: 1 addition & 0 deletions Include/opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.10b1 3436 (Add GEN_START bytecode #43683)
# Python 3.10b1 3437 (Undo making 'annotations' future by default - We like to dance among core devs!)
# Python 3.10b1 3438 Safer line number table handling.
# Python 3.10b1 3439 (Add ROT_N)

#
# MAGIC must change whenever the bytecode emitted by the compiler may no
Expand All @@ -360,7 +361,7 @@ def _write_atomic(path, data, mode=0o666):
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated.

MAGIC_NUMBER = (3438).to_bytes(2, 'little') + b'\r\n'
MAGIC_NUMBER = (3439).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c

_PYCACHE = '__pycache__'
Expand Down
2 changes: 1 addition & 1 deletion Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def jabs_op(name, op):
name_op('DELETE_ATTR', 96) # ""
name_op('STORE_GLOBAL', 97) # ""
name_op('DELETE_GLOBAL', 98) # ""

def_op('ROT_N', 99)
def_op('LOAD_CONST', 100) # Index in const list
hasconst.append(100)
name_op('LOAD_NAME', 101) # Index in name list
Expand Down
80 changes: 77 additions & 3 deletions Lib/test/test_patma.py
Original file line number Diff line number Diff line change
Expand Up @@ -2905,6 +2905,79 @@ def test_patma_288(self):
pass
""")

def test_patma_289(self):
x = {"y": 1}
match x:
case {"y": (0 as y) | (1 as y)}:
z = 0
self.assertEqual(x, {"y": 1})
self.assertEqual(y, 1)
self.assertEqual(z, 0)

@no_perf
def test_patma_290(self):
self.assert_syntax_error("""
match ...:
case [a, [b] | [c] | [d]]:
pass
""")

@no_perf
def test_patma_291(self):
# Hunting for leaks using -R doesn't catch leaks in the compiler itself,
# just the code under test. This test ensures that if there are leaks in
# the pattern compiler, those runs will fail:
with open(__file__) as file:
compile(file.read(), __file__, "exec")

def test_patma_292(self):
def f(x):
match x:
case ((a, b, c, d, e, f, g, h, i, 9) |
(h, g, i, a, b, d, e, c, f, 10) |
(g, b, a, c, d, -5, e, h, i, f) |
(-1, d, f, b, g, e, i, a, h, c)):
w = 0
out = locals()
del out["x"]
return out
alts = [
dict(a=0, b=1, c=2, d=3, e=4, f=5, g=6, h=7, i=8, w=0),
dict(h=1, g=2, i=3, a=4, b=5, d=6, e=7, c=8, f=9, w=0),
dict(g=0, b=-1, a=-2, c=-3, d=-4, e=-6, h=-7, i=-8, f=-9, w=0),
dict(d=-2, f=-3, b=-4, g=-5, e=-6, i=-7, a=-8, h=-9, c=-10, w=0),
dict(),
]
self.assertEqual(f(range(10)), alts[0])
self.assertEqual(f(range(1, 11)), alts[1])
self.assertEqual(f(range(0, -10, -1)), alts[2])
self.assertEqual(f(range(-1, -11, -1)), alts[3])
self.assertEqual(f(range(10, 20)), alts[4])

def test_patma_293(self):
def f(x):
match x:
case [y, (a, b, c, d, e, f, g, h, i, 9) |
(h, g, i, a, b, d, e, c, f, 10) |
(g, b, a, c, d, -5, e, h, i, f) |
(-1, d, f, b, g, e, i, a, h, c), z]:
w = 0
out = locals()
del out["x"]
return out
alts = [
dict(a=0, b=1, c=2, d=3, e=4, f=5, g=6, h=7, i=8, w=0, y=False, z=True),
dict(h=1, g=2, i=3, a=4, b=5, d=6, e=7, c=8, f=9, w=0, y=False, z=True),
dict(g=0, b=-1, a=-2, c=-3, d=-4, e=-6, h=-7, i=-8, f=-9, w=0, y=False, z=True),
dict(d=-2, f=-3, b=-4, g=-5, e=-6, i=-7, a=-8, h=-9, c=-10, w=0, y=False, z=True),
dict(),
]
self.assertEqual(f((False, range(10), True)), alts[0])
self.assertEqual(f((False, range(1, 11), True)), alts[1])
self.assertEqual(f((False, range(0, -10, -1), True)), alts[2])
self.assertEqual(f((False, range(-1, -11, -1), True)), alts[3])
self.assertEqual(f((False, range(10, 20), True)), alts[4])


class PerfPatma(TestPatma):

Expand Down Expand Up @@ -2936,7 +3009,8 @@ def setUpClass():


"""
sudo ./python -m pyperf system tune && \
./python -m pyperf timeit --rigorous --setup "from test.test_patma import PerfPatma; p = PerfPatma()" "p.run_perf()"; \
sudo ./python -m pyperf system reset
# From inside venv pointing to this Python, with pyperf installed:
sudo $(which python) -m pyperf system tune && \
$(which python) -m pyperf timeit --rigorous --setup "from test.test_patma import PerfPatma; p = PerfPatma()" "p.run_perf()"; \
sudo $(which python) -m pyperf system reset
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
When performing structural pattern matching (:pep:`634`), captured names are
now left unbound until the *entire* pattern has matched successfully.
8 changes: 8 additions & 0 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -4399,6 +4399,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
DISPATCH();
}

case TARGET(ROT_N): {
PyObject *top = TOP();
memmove(&PEEK(oparg - 1), &PEEK(oparg),
sizeof(PyObject*) * (oparg - 1));
PEEK(oparg) = top;
DISPATCH();
}

case TARGET(EXTENDED_ARG): {
int oldoparg = oparg;
NEXTOPARG();
Expand Down
Loading