diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2016-10-02 08:06:43 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2016-10-02 08:06:43 (GMT) |
commit | e036ef8fa29f27d57fe9f8cef8d931d4122d8223 (patch) | |
tree | b3d48b866f7339d7577f68529326fba4856b821e /Python | |
parent | 0a3beffc8f6483da16523fceb9158af6a259a608 (diff) | |
download | cpython-e036ef8fa29f27d57fe9f8cef8d931d4122d8223.zip cpython-e036ef8fa29f27d57fe9f8cef8d931d4122d8223.tar.gz cpython-e036ef8fa29f27d57fe9f8cef8d931d4122d8223.tar.bz2 |
Issue #27358: Optimized merging var-keyword arguments and improved error
message when pass a non-mapping as a var-keyword argument.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/ceval.c | 98 |
1 files changed, 54 insertions, 44 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index 717ac33..c443305 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2710,9 +2710,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) DISPATCH(); } - TARGET(BUILD_MAP_UNPACK_WITH_CALL) TARGET(BUILD_MAP_UNPACK) { - int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL; Py_ssize_t i; PyObject *sum = PyDict_New(); if (sum == NULL) @@ -2720,55 +2718,67 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) for (i = oparg; i > 0; i--) { PyObject *arg = PEEK(i); - if (with_call && PyDict_Size(sum)) { - PyObject *intersection = _PyDictView_Intersect(sum, arg); - - if (intersection == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyObject *func = PEEK(2 + oparg); - PyErr_Format(PyExc_TypeError, - "%.200s%.200s argument after ** " - "must be a mapping, not %.200s", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - arg->ob_type->tp_name); - } - Py_DECREF(sum); - goto error; - } - - if (PySet_GET_SIZE(intersection)) { - Py_ssize_t idx = 0; - PyObject *key; - PyObject *func = PEEK(2 + oparg); - Py_hash_t hash; - _PySet_NextEntry(intersection, &idx, &key, &hash); - if (!PyUnicode_Check(key)) { - PyErr_Format(PyExc_TypeError, - "%.200s%.200s keywords must be strings", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func)); - } else { - PyErr_Format(PyExc_TypeError, - "%.200s%.200s got multiple " - "values for keyword argument '%U'", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - key); - } - Py_DECREF(intersection); - Py_DECREF(sum); - goto error; + if (PyDict_Update(sum, arg) < 0) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Format(PyExc_TypeError, + "'%.200s' object is not a mapping1", + arg->ob_type->tp_name); } - Py_DECREF(intersection); + Py_DECREF(sum); + goto error; } + } - if (PyDict_Update(sum, arg) < 0) { + while (oparg--) + Py_DECREF(POP()); + PUSH(sum); + DISPATCH(); + } + + TARGET(BUILD_MAP_UNPACK_WITH_CALL) { + Py_ssize_t i; + PyObject *sum = PyDict_New(); + if (sum == NULL) + goto error; + + for (i = oparg; i > 0; i--) { + PyObject *arg = PEEK(i); + if (_PyDict_MergeEx(sum, arg, 2) < 0) { + PyObject *func = PEEK(2 + oparg); if (PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Format(PyExc_TypeError, - "'%.200s' object is not a mapping", + "%.200s%.200s argument after ** " + "must be a mapping, not %.200s", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), arg->ob_type->tp_name); } + else if (PyErr_ExceptionMatches(PyExc_KeyError)) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + if (val && PyTuple_Check(val) && PyTuple_GET_SIZE(val) == 1) { + PyObject *key = PyTuple_GET_ITEM(val, 0); + if (!PyUnicode_Check(key)) { + PyErr_Format(PyExc_TypeError, + "%.200s%.200s keywords must be strings", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func)); + } else { + PyErr_Format(PyExc_TypeError, + "%.200s%.200s got multiple " + "values for keyword argument '%U'", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + key); + } + Py_XDECREF(exc); + Py_XDECREF(val); + Py_XDECREF(tb); + } + else { + PyErr_Restore(exc, val, tb); + } + } Py_DECREF(sum); goto error; } |