8000 [3.10] bpo-44600: Fix line numbers for pattern matching cleanup code … · python/cpython@01601aa · GitHub
[go: up one dir, main page]

Skip to content

Commit 01601aa

Browse files
[3.10] bpo-44600: Fix line numbers for pattern matching cleanup code (GH-27346) (GH-27356)
(cherry picked from commit 4214f47) Co-authored-by: Charles Burkland <charles.aburkland@gmail.com> Automerge-Triggered-By: GH:brandtbucher
1 parent 628baf6 commit 01601aa

File tree

3 files changed

+89
-4
lines changed

3 files changed

+89
-4
lines changed

Lib/test/test_patma.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import dataclasses
44
import enum
55
import inspect
6+
import sys
67
import unittest
78

89

@@ -3056,6 +3057,81 @@ class Keys:
30563057
self.assertIs(z, None)
30573058

30583059

3060+
class TestTracing(unittest.TestCase):
3061+
3062+
def _test_trace(self, func, expected_linenos, *f_args):
3063+
actual_linenos = set()
3064+
def trace(frame, event, arg):
3065+
if frame.f_code.co_name == func.__name__:
3066+
relative_lineno = frame.f_lineno - func.__code__.co_firstlineno
3067+
actual_linenos.add(relative_lineno)
3068+
return trace
3069+
3070+
sys.settrace(trace)
3071+
func(*f_args)
3072+
sys.settrace(None)
3073+
self.assertSetEqual(actual_linenos, expected_linenos)
3074+
3075+
def test_default_case_traces_correctly_a(self):
3076+
def default_no_assign(command): # 0
3077+
match command.split(): # 1
3078+
case ["go", direction] if direction in "nesw": # 2
3079+
return f"go {direction}" # 3
3080+
case ["go", _]: # 4
3081+
return "no go" # 5
3082+
case _: # 6
3083+
return "default" # 7
3084+
3085+
self._test_trace(default_no_assign, {0, 1, 2, 3}, "go n")
3086+
self._test_trace(default_no_assign, {0, 1, 2, 4, 5}, "go x")
3087+
self._test_trace(default_no_assign, {0, 1, 2, 4, 6, 7}, "spam")
3088+
3089+
def test_default_case_traces_correctly_b(self):
3090+
def default_wildcard_assign(command): # 0
3091+
match command.split(): # 1
3092+
case ["go", direction] if direction in "nesw": # 2
3093+
return f"go {direction}" # 3
3094+
case ["go", _]: # 4
3095+
return "no go" # 5
3096+
case x: # 6
3097+
return x # 7
3098+
3099+
self._test_trace(default_wildcard_assign, {0, 1, 2, 3}, "go n")
3100+
self._test_trace(default_wildcard_assign, {0, 1, 2, 4, 5}, "go x")
3101+
self._test_trace(default_wildcard_assign, {0, 1, 2, 4, 6, 7}, "spam")
3102+
3103+
def test_default_case_traces_correctly_c(self):
3104+
def no_default(command): # 0
3105+
match command.split(): # 1
3106+
case ["go", direction] if direction in "nesw": # 2
3107+
return f"go {direction}" # 3
3108+
case ["go", _]: # 4
3109+
return "no go" # 5
3110+
3111+
self._test_trace(no_default, {0, 1, 2, 3}, "go n")
3112+
self._test_trace(no_default, {0, 1, 2, 4, 5}, "go x")
3113+
self._test_trace(no_default, {0, 1, 2, 4}, "spam")
3114+
3115+
def test_default_case_traces_correctly_d(self):
3116+
def only_default_no_assign(command): # 0
3117+
match command.split(): # 1
3118+
case _: # 2
3119+
return "default" # 3
3120+
3121+
self._test_trace(only_default_no_assign, {0, 1, 2, 3}, "go n")
3122+
self._test_trace(only_default_no_assign, {0, 1, 2, 3} , "go x")
3123+
self._test_trace(only_default_no_assign, {0, 1, 2, 3} EDBE , "spam")
3124+
3125+
def test_default_case_traces_correctly_e(self):
3126+
def only_default_wildcard_assign(command): # 0
3127+
match command.split(): # 1
3128+
case x: # 2
3129+
return x # 3
3130+
3131+
self._test_trace(only_default_wildcard_assign, {0, 1, 2, 3}, "go n")
3132+
self._test_trace(only_default_wildcard_assign, {0, 1, 2, 3} , "go x")
3133+
self._test_trace(only_default_wildcard_assign, {0, 1, 2, 3}, "spam")
3134+
30593135
if __name__ == "__main__":
30603136
"""
30613137
# From inside environment using this Python, with pyperf installed:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix incorrect line numbers while tracing some failed patterns in :ref:`match <match>` statements. Patch by Charles Burkland.

Python/compile.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6398,17 +6398,25 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc)
63986398
}
63996399
VISIT_SEQ(c, stmt, m->body);
64006400
ADDOP_JUMP(c, JUMP_FORWARD, end);
6401+
// If the pattern fails to match, we want the line number of the
6402+
// cleanup to be associated with the failed pattern, not the last line
6403+
// of the body
6404+
SET_LOC(c, m->pattern);
64016405
RETURN_IF_FALSE(emit_and_reset_fail_pop(c, pc));
64026406
}
64036407
if (has_default) {
6404-
if (cases == 1) {
6405-
// No matches. Done with the subject:
6406-
ADDOP(c, POP_TOP);
6407-
}
64086408
// A trailing "case _" is common, and lets us save a bit of redundant
64096409
// pushing and popping in the loop above:
64106410
m = asdl_seq_GET(s->v.Match.cases, cases - 1);
64116411
SET_LOC(c, m->pattern);
6412+
if (cases == 1) {
6413+
// No matches. Done with the subject:
6414+
ADDOP(c, POP_TOP);
6415+
}
6416+
else {
6417+
// Show line coverage for default case (it doesn't create bytecode)
6418+
ADDOP(c, NOP);
6419+
}
64126420
if (m->guard) {
64136421
RETURN_IF_FALSE(compiler_jump_if(c, m->guard, end, 0));
64146422
}

0 commit comments

Comments
 (0)
0