From 696d0bd002f33410679f0d6f55365094fe490233 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 30 Aug 2021 00:19:02 +0900 Subject: [PATCH 1/4] bpo-45045: Optimize mapping patterns of structural pattern matching --- Python/ceval.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 5fec90b10483ab..d77ebb60d852c8 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -859,7 +859,7 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys) if (dummy == NULL) { goto fail; } - values = PyList_New(0); + values = PyTuple_New(nkeys); if (values == NULL) { goto fail; } @@ -873,7 +873,8 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys) } goto fail; } - PyObject *value = PyObject_CallFunctionObjArgs(get, key, dummy, NULL); + PyObject *args[] = { key, dummy }; + PyObject *value = PyObject_Vectorcall(get, args, 2, NULL); if (value == NULL) { goto fail; } @@ -886,10 +887,8 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys) values = Py_None; goto done; } - PyList_Append(values, value); - Py_DECREF(value); + PyTuple_SET_ITEM(values, i, value); } - Py_SETREF(values, PyList_AsTuple(values)); // Success: done: Py_DECREF(get); From c95a7eaf50acffa258cc09cfaa49dca8673b8277 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 30 Aug 2021 01:51:12 +0900 Subject: [PATCH 2/4] bpo-45045: Address code review --- Python/ceval.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index d77ebb60d852c8..85c4495ee7cbfc 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -846,7 +846,9 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys) // - Don't cause key creation or resizing in dict subclasses like // collections.defaultdict that define __missing__ (or similar). _Py_IDENTIFIER(get); - PyObject *get = _PyObject_GetAttrId(map, &PyId_get); + PyObject *get_name = _PyUnicode_FromId(&PyId_get); // borrowed + PyObject *get = NULL; + int meth_found = _PyObject_GetMethod(map, get_name, &get); if (get == NULL) { goto fail; } @@ -873,8 +875,14 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys) } goto fail; } - PyObject *args[] = { key, dummy }; - PyObject *value = PyObject_Vectorcall(get, args, 2, NULL); + PyObject *args[] = { map, key, dummy }; + PyObject *value = NULL; + if (meth_found) { + value = PyObject_Vectorcall(get, args, 3, NULL); + } + else { + value = PyObject_Vectorcall(get, &args[1], 2, NULL); + } if (value == NULL) { goto fail; } From 7a304965599065e168a1aa6b96c53e58e46efc92 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 30 Aug 2021 02:25:43 +0900 Subject: [PATCH 3/4] bpo-45045 Add unbound method test case --- Lib/test/test_patma.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py index aa18e29e22548f..57d3b1ec701ca4 100644 --- a/Lib/test/test_patma.py +++ b/Lib/test/test_patma.py @@ -2641,6 +2641,19 @@ def f(x): self.assertEqual(f((False, range(-1, -11, -1), True)), alts[3]) self.assertEqual(f((False, range(10, 20), True)), alts[4]) + def test_patma_248(self): + class C(dict): + @staticmethod + def get(key, default=None): + return 'bar' + + x = C({'foo': 'bar'}) + match x: + case {'foo': bar}: + y = bar + + self.assertEqual(y, 'bar') + class TestSyntaxErrors(unittest.TestCase): From 71fe76d9f35fa2a222e0fcf371ae5c23fe7eac43 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 30 Aug 2021 12:31:27 +0900 Subject: [PATCH 4/4] bpo-45045: nit --- Python/ceval.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 85c4495ee7cbfc..0ea85cdc174bde 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -841,13 +841,17 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys) PyObject *seen = NULL; PyObject *dummy = NULL; PyObject *values = NULL; + PyObject *get_name = NULL; + PyObject *get = NULL; // We use the two argument form of map.get(key, default) for two reasons: // - Atomically check for a key and get its value without error handling. // - Don't cause key creation or resizing in dict subclasses like // collections.defaultdict that define __missing__ (or similar). _Py_IDENTIFIER(get); - PyObject *get_name = _PyUnicode_FromId(&PyId_get); // borrowed - PyObject *get = NULL; + get_name = _PyUnicode_FromId(&PyId_get); // borrowed + if (get_name == NULL) { + return NULL; + } int meth_found = _PyObject_GetMethod(map, get_name, &get); if (get == NULL) { goto fail;