mirror of
https://github.com/python/cpython.git
synced 2025-12-23 09:19:18 +00:00
Merge 9375e2b27e into f9704f1d84
This commit is contained in:
commit
d5e9695561
3 changed files with 45 additions and 31 deletions
|
|
@ -2345,6 +2345,12 @@ Invalid pattern matching constructs:
|
|||
Traceback (most recent call last):
|
||||
SyntaxError: positional patterns follow keyword patterns
|
||||
|
||||
>>> match ...:
|
||||
... case Foo(y=1, x=2, y=3):
|
||||
... ...
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: attribute name repeated in class pattern: y
|
||||
|
||||
>>> match ...:
|
||||
... case C(a=b, c, d=e, f, g=h, i, j=k, ...):
|
||||
... ...
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Improve :opcode:`MATCH_CLASS` performance by up to 52% in certain cases. Patch by Marc Mueller.
|
||||
|
|
@ -844,15 +844,18 @@ match_class_attr(PyThreadState *tstate, PyObject *subject, PyObject *type,
|
|||
PyObject *name, PyObject *seen)
|
||||
{
|
||||
assert(PyUnicode_CheckExact(name));
|
||||
assert(PySet_CheckExact(seen));
|
||||
if (PySet_Contains(seen, name) || PySet_Add(seen, name)) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
// Seen it before!
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"%s() got multiple sub-patterns for attribute %R",
|
||||
((PyTypeObject*)type)->tp_name, name);
|
||||
// Only check for duplicates if seen is not NULL.
|
||||
if (seen != NULL) {
|
||||
assert(PySet_CheckExact(seen));
|
||||
if (PySet_Contains(seen, name) || PySet_Add(seen, name)) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
// Seen it before!
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"%s() got multiple sub-patterns for attribute %R",
|
||||
((PyTypeObject*)type)->tp_name, name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
PyObject *attr;
|
||||
(void)PyObject_GetOptionalAttr(subject, name, &attr);
|
||||
|
|
@ -875,14 +878,26 @@ _PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type,
|
|||
if (PyObject_IsInstance(subject, type) <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
// So far so good:
|
||||
PyObject *seen = PySet_New(NULL);
|
||||
if (seen == NULL) {
|
||||
return NULL;
|
||||
// Short circuit if there aren't any arguments:
|
||||
Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwargs);
|
||||
Py_ssize_t nattrs = nargs + nkwargs;
|
||||
if (!nattrs) {
|
||||
return PyTuple_New(0);
|
||||
}
|
||||
PyObject *attrs = PyList_New(0);
|
||||
// So far so good:
|
||||
PyObject *seen = NULL;
|
||||
// Only check for duplicates if there is at least one positional attribute
|
||||
// and two or more attributes in total. Duplicate keyword attributes are
|
||||
// detected during the compile stage and raise a SyntaxError.
|
||||
if (nargs > 0 && nattrs > 1) {
|
||||
seen = PySet_New(NULL);
|
||||
if (seen == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
PyObject *attrs = PyTuple_New(nattrs);
|
||||
if (attrs == NULL) {
|
||||
Py_DECREF(seen);
|
||||
Py_XDECREF(seen);
|
||||
return NULL;
|
||||
}
|
||||
// NOTE: From this point on, goto fail on failure:
|
||||
|
|
@ -923,9 +938,8 @@ _PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type,
|
|||
}
|
||||
if (match_self) {
|
||||
// Easy. Copy the subject itself, and move on to kwargs.
|
||||
if (PyList_Append(attrs, subject) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
assert(PyTuple_GET_ITEM(attrs, 0) == NULL);
|
||||
PyTuple_SET_ITEM(attrs, 0, Py_NewRef(subject));
|
||||
}
|
||||
else {
|
||||
for (Py_ssize_t i = 0; i < nargs; i++) {
|
||||
|
|
@ -941,36 +955,29 @@ _PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type,
|
|||
if (attr == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
if (PyList_Append(attrs, attr) < 0) {
|
||||
Py_DECREF(attr);
|
||||
goto fail;
|
||||
}
|
||||
Py_DECREF(attr);
|
||||
assert(PyTuple_GET_ITEM(attrs, i) == NULL);
|
||||
PyTuple_SET_ITEM(attrs, i, attr);
|
||||
}
|
||||
}
|
||||
Py_CLEAR(match_args);
|
||||
}
|
||||
// Finally, the keyword subpatterns:
|
||||
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(kwargs); i++) {
|
||||
for (Py_ssize_t i = 0; i < nkwargs; i++) {
|
||||
PyObject *name = PyTuple_GET_ITEM(kwargs, i);
|
||||
PyObject *attr = match_class_attr(tstate, subject, type, name, seen);
|
||||
if (attr == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
if (PyList_Append(attrs, attr) < 0) {
|
||||
Py_DECREF(attr);
|
||||
goto fail;
|
||||
}
|
||||
Py_DECREF(attr);
|
||||
assert(PyTuple_GET_ITEM(attrs, nargs + i) == NULL);
|
||||
PyTuple_SET_ITEM(attrs, nargs + i, attr);
|
||||
}
|
||||
Py_SETREF(attrs, PyList_AsTuple(attrs));
|
||||
Py_DECREF(seen);
|
||||
Py_XDECREF(seen);
|
||||
return attrs;
|
||||
fail:
|
||||
// We really don't care whether an error was raised or not... that's our
|
||||
// caller's problem. All we know is that the match failed.
|
||||
Py_XDECREF(match_args);
|
||||
Py_DECREF(seen);
|
||||
Py_XDECREF(seen);
|
||||
Py_DECREF(attrs);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue