Issue #27213: Fixed different issues with reworked CALL_FUNCTION* opcodes.
* BUILD_TUPLE_UNPACK and BUILD_MAP_UNPACK_WITH_CALL no longer generated with single tuple or dict. * Restored more informative error messages for incorrect var-positional and var-keyword arguments. * Removed code duplications in _PyEval_EvalCodeWithName(). * Removed redundant runtime checks and parameters in _PyStack_AsDict(). * Added a workaround and enabled previously disabled test in test_traceback. * Removed dead code from the dis module.
This commit is contained in:
parent
29097d5a6a
commit
b72810583e
|
@ -275,9 +275,7 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
|
||||||
|
|
||||||
PyAPI_FUNC(PyObject *) _PyStack_AsDict(
|
PyAPI_FUNC(PyObject *) _PyStack_AsDict(
|
||||||
PyObject **values,
|
PyObject **values,
|
||||||
Py_ssize_t nkwargs,
|
PyObject *kwnames);
|
||||||
PyObject *kwnames,
|
|
||||||
PyObject *func);
|
|
||||||
|
|
||||||
/* Convert (args, nargs, kwargs) into a (stack, nargs, kwnames).
|
/* Convert (args, nargs, kwargs) into a (stack, nargs, kwnames).
|
||||||
|
|
||||||
|
|
|
@ -314,8 +314,6 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
|
||||||
argrepr = argval
|
argrepr = argval
|
||||||
elif op in hasfree:
|
elif op in hasfree:
|
||||||
argval, argrepr = _get_name_info(arg, cells)
|
argval, argrepr = _get_name_info(arg, cells)
|
||||||
elif op in hasnargs: # unused
|
|
||||||
argrepr = "%d positional, %d keyword pair" % (arg%256, arg//256)
|
|
||||||
yield Instruction(opname[op], op,
|
yield Instruction(opname[op], op,
|
||||||
arg, argval, argrepr,
|
arg, argval, argrepr,
|
||||||
offset, starts_line, is_jump_target)
|
offset, starts_line, is_jump_target)
|
||||||
|
|
|
@ -118,7 +118,7 @@ Verify clearing of SF bug #733667
|
||||||
>>> g(*Nothing())
|
>>> g(*Nothing())
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: 'Nothing' object is not iterable
|
TypeError: g() argument after * must be an iterable, not Nothing
|
||||||
|
|
||||||
>>> class Nothing:
|
>>> class Nothing:
|
||||||
... def __len__(self): return 5
|
... def __len__(self): return 5
|
||||||
|
@ -127,7 +127,7 @@ Verify clearing of SF bug #733667
|
||||||
>>> g(*Nothing())
|
>>> g(*Nothing())
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: 'Nothing' object is not iterable
|
TypeError: g() argument after * must be an iterable, not Nothing
|
||||||
|
|
||||||
>>> class Nothing():
|
>>> class Nothing():
|
||||||
... def __len__(self): return 5
|
... def __len__(self): return 5
|
||||||
|
@ -231,32 +231,34 @@ What about willful misconduct?
|
||||||
>>> h(*h)
|
>>> h(*h)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: 'function' object is not iterable
|
TypeError: h() argument after * must be an iterable, not function
|
||||||
|
|
||||||
>>> dir(*h)
|
>>> dir(*h)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: 'function' object is not iterable
|
TypeError: dir() argument after * must be an iterable, not function
|
||||||
|
|
||||||
>>> None(*h)
|
>>> None(*h)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: 'function' object is not iterable
|
TypeError: NoneType object argument after * must be an iterable, \
|
||||||
|
not function
|
||||||
|
|
||||||
>>> h(**h)
|
>>> h(**h)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: 'function' object is not a mapping
|
TypeError: h() argument after ** must be a mapping, not function
|
||||||
|
|
||||||
>>> dir(**h)
|
>>> dir(**h)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: 'function' object is not a mapping
|
TypeError: dir() argument after ** must be a mapping, not function
|
||||||
|
|
||||||
>>> None(**h)
|
>>> None(**h)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: 'function' object is not a mapping
|
TypeError: NoneType object argument after ** must be a mapping, \
|
||||||
|
not function
|
||||||
|
|
||||||
>>> dir(b=1, **{'b': 1})
|
>>> dir(b=1, **{'b': 1})
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
|
|
|
@ -304,7 +304,6 @@ class TracebackFormatTests(unittest.TestCase):
|
||||||
])
|
])
|
||||||
|
|
||||||
# issue 26823 - Shrink recursive tracebacks
|
# issue 26823 - Shrink recursive tracebacks
|
||||||
@unittest.skipIf(True, "FIXME: test broken, see issue #28050")
|
|
||||||
def _check_recursive_traceback_display(self, render_exc):
|
def _check_recursive_traceback_display(self, render_exc):
|
||||||
# Always show full diffs when this test fails
|
# Always show full diffs when this test fails
|
||||||
# Note that rearranging things may require adjusting
|
# Note that rearranging things may require adjusting
|
||||||
|
@ -353,7 +352,7 @@ class TracebackFormatTests(unittest.TestCase):
|
||||||
|
|
||||||
# Check the recursion count is roughly as expected
|
# Check the recursion count is roughly as expected
|
||||||
rec_limit = sys.getrecursionlimit()
|
rec_limit = sys.getrecursionlimit()
|
||||||
self.assertIn(int(re.search(r"\d+", actual[-2]).group()), range(rec_limit-50, rec_limit))
|
self.assertIn(int(re.search(r"\d+", actual[-2]).group()), range(rec_limit-60, rec_limit))
|
||||||
|
|
||||||
# Check a known (limited) number of recursive invocations
|
# Check a known (limited) number of recursive invocations
|
||||||
def g(count=10):
|
def g(count=10):
|
||||||
|
|
|
@ -2367,9 +2367,9 @@ _PyObject_Call_Prepend(PyObject *func,
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames,
|
_PyStack_AsDict(PyObject **values, PyObject *kwnames)
|
||||||
PyObject *func)
|
|
||||||
{
|
{
|
||||||
|
Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames);
|
||||||
PyObject *kwdict;
|
PyObject *kwdict;
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
|
|
||||||
|
@ -2378,24 +2378,12 @@ _PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i < nkwargs; i++) {
|
for (i = 0; i < nkwargs; i++) {
|
||||||
int err;
|
|
||||||
PyObject *key = PyTuple_GET_ITEM(kwnames, i);
|
PyObject *key = PyTuple_GET_ITEM(kwnames, i);
|
||||||
PyObject *value = *values++;
|
PyObject *value = *values++;
|
||||||
|
assert(PyUnicode_CheckExact(key));
|
||||||
if (PyDict_GetItem(kwdict, key) != NULL) {
|
assert(PyDict_GetItem(kwdict, key) == NULL);
|
||||||
PyErr_Format(PyExc_TypeError,
|
if (PyDict_SetItem(kwdict, key, value)) {
|
||||||
"%.200s%s got multiple values "
|
|
||||||
"for keyword argument '%U'",
|
|
||||||
PyEval_GetFuncName(func),
|
|
||||||
PyEval_GetFuncDesc(func),
|
|
||||||
key);
|
|
||||||
Py_DECREF(kwdict);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = PyDict_SetItem(kwdict, key, value);
|
|
||||||
if (err) {
|
|
||||||
Py_DECREF(kwdict);
|
Py_DECREF(kwdict);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -2479,7 +2467,7 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nkwargs > 0) {
|
if (nkwargs > 0) {
|
||||||
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
|
kwdict = _PyStack_AsDict(stack + nargs, kwnames);
|
||||||
if (kwdict == NULL) {
|
if (kwdict == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,7 +279,7 @@ _PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack,
|
||||||
|
|
||||||
nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
|
nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
|
||||||
if (nkwargs > 0) {
|
if (nkwargs > 0) {
|
||||||
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
|
kwdict = _PyStack_AsDict(stack + nargs, kwnames);
|
||||||
if (kwdict == NULL) {
|
if (kwdict == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
141
Python/ceval.c
141
Python/ceval.c
|
@ -2513,14 +2513,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
||||||
TARGET(BUILD_LIST_UNPACK) {
|
TARGET(BUILD_LIST_UNPACK) {
|
||||||
int convert_to_tuple = opcode == BUILD_TUPLE_UNPACK;
|
int convert_to_tuple = opcode == BUILD_TUPLE_UNPACK;
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
PyObject *sum;
|
PyObject *sum = PyList_New(0);
|
||||||
PyObject *return_value;
|
PyObject *return_value;
|
||||||
|
|
||||||
if (convert_to_tuple && oparg == 1 && PyTuple_CheckExact(TOP())) {
|
|
||||||
DISPATCH();
|
|
||||||
}
|
|
||||||
|
|
||||||
sum = PyList_New(0);
|
|
||||||
if (sum == NULL)
|
if (sum == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -2708,13 +2703,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
||||||
TARGET(BUILD_MAP_UNPACK) {
|
TARGET(BUILD_MAP_UNPACK) {
|
||||||
int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL;
|
int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL;
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
PyObject *sum;
|
PyObject *sum = PyDict_New();
|
||||||
|
|
||||||
if (with_call && oparg == 1 && PyDict_CheckExact(TOP())) {
|
|
||||||
DISPATCH();
|
|
||||||
}
|
|
||||||
|
|
||||||
sum = PyDict_New();
|
|
||||||
if (sum == NULL)
|
if (sum == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -3290,11 +3279,53 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
||||||
PCALL(PCALL_ALL);
|
PCALL(PCALL_ALL);
|
||||||
if (oparg & 0x01) {
|
if (oparg & 0x01) {
|
||||||
kwargs = POP();
|
kwargs = POP();
|
||||||
|
if (!PyDict_CheckExact(kwargs)) {
|
||||||
|
PyObject *d = PyDict_New();
|
||||||
|
if (d == NULL)
|
||||||
|
goto error;
|
||||||
|
if (PyDict_Update(d, kwargs) != 0) {
|
||||||
|
Py_DECREF(d);
|
||||||
|
/* PyDict_Update raises attribute
|
||||||
|
* error (percolated from an attempt
|
||||||
|
* to get 'keys' attribute) instead of
|
||||||
|
* a type error if its second argument
|
||||||
|
* is not a mapping.
|
||||||
|
*/
|
||||||
|
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||||
|
func = SECOND();
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"%.200s%.200s argument after ** "
|
||||||
|
"must be a mapping, not %.200s",
|
||||||
|
PyEval_GetFuncName(func),
|
||||||
|
PyEval_GetFuncDesc(func),
|
||||||
|
kwargs->ob_type->tp_name);
|
||||||
|
}
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
Py_DECREF(kwargs);
|
||||||
|
kwargs = d;
|
||||||
|
}
|
||||||
assert(PyDict_CheckExact(kwargs));
|
assert(PyDict_CheckExact(kwargs));
|
||||||
}
|
}
|
||||||
callargs = POP();
|
callargs = POP();
|
||||||
assert(PyTuple_CheckExact(callargs));
|
|
||||||
func = TOP();
|
func = TOP();
|
||||||
|
if (!PyTuple_Check(callargs)) {
|
||||||
|
if (Py_TYPE(callargs)->tp_iter == NULL &&
|
||||||
|
!PySequence_Check(callargs)) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"%.200s%.200s argument after * "
|
||||||
|
"must be an iterable, not %.200s",
|
||||||
|
PyEval_GetFuncName(func),
|
||||||
|
PyEval_GetFuncDesc(func),
|
||||||
|
callargs->ob_type->tp_name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
Py_SETREF(callargs, PySequence_Tuple(callargs));
|
||||||
|
if (callargs == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(PyTuple_Check(callargs));
|
||||||
|
|
||||||
result = do_call_core(func, callargs, kwargs);
|
result = do_call_core(func, callargs, kwargs);
|
||||||
Py_DECREF(func);
|
Py_DECREF(func);
|
||||||
|
@ -3796,8 +3827,8 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount,
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
_PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
PyObject **args, Py_ssize_t argcount,
|
PyObject **args, Py_ssize_t argcount,
|
||||||
PyObject **kws, Py_ssize_t kwcount,
|
PyObject **kwnames, PyObject **kwargs,
|
||||||
PyObject *kwnames, PyObject **kwstack,
|
Py_ssize_t kwcount, int kwstep,
|
||||||
PyObject **defs, Py_ssize_t defcount,
|
PyObject **defs, Py_ssize_t defcount,
|
||||||
PyObject *kwdefs, PyObject *closure,
|
PyObject *kwdefs, PyObject *closure,
|
||||||
PyObject *name, PyObject *qualname)
|
PyObject *name, PyObject *qualname)
|
||||||
|
@ -3811,9 +3842,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
|
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
|
||||||
Py_ssize_t i, n;
|
Py_ssize_t i, n;
|
||||||
PyObject *kwdict;
|
PyObject *kwdict;
|
||||||
Py_ssize_t kwcount2 = kwnames == NULL ? 0 : PyTuple_GET_SIZE(kwnames);
|
|
||||||
|
|
||||||
assert((kwcount == 0) || (kws != NULL));
|
|
||||||
|
|
||||||
if (globals == NULL) {
|
if (globals == NULL) {
|
||||||
PyErr_SetString(PyExc_SystemError,
|
PyErr_SetString(PyExc_SystemError,
|
||||||
|
@ -3873,11 +3901,12 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle keyword arguments passed as an array of (key, value) pairs */
|
/* Handle keyword arguments passed as two strided arrays */
|
||||||
for (i = 0; i < kwcount; i++) {
|
kwcount *= kwstep;
|
||||||
|
for (i = 0; i < kwcount; i += kwstep) {
|
||||||
PyObject **co_varnames;
|
PyObject **co_varnames;
|
||||||
PyObject *keyword = kws[2*i];
|
PyObject *keyword = kwnames[i];
|
||||||
PyObject *value = kws[2*i + 1];
|
PyObject *value = kwargs[i];
|
||||||
Py_ssize_t j;
|
Py_ssize_t j;
|
||||||
|
|
||||||
if (keyword == NULL || !PyUnicode_Check(keyword)) {
|
if (keyword == NULL || !PyUnicode_Check(keyword)) {
|
||||||
|
@ -3932,61 +3961,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
SETLOCAL(j, value);
|
SETLOCAL(j, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle keyword arguments passed as keys tuple + values array */
|
|
||||||
for (i = 0; i < kwcount2; i++) {
|
|
||||||
PyObject **co_varnames;
|
|
||||||
PyObject *keyword = PyTuple_GET_ITEM(kwnames, i);
|
|
||||||
PyObject *value = kwstack[i];
|
|
||||||
int j;
|
|
||||||
if (keyword == NULL || !PyUnicode_Check(keyword)) {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"%U() keywords must be strings",
|
|
||||||
co->co_name);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
/* Speed hack: do raw pointer compares. As names are
|
|
||||||
normally interned this should almost always hit. */
|
|
||||||
co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item;
|
|
||||||
for (j = 0; j < total_args; j++) {
|
|
||||||
PyObject *nm = co_varnames[j];
|
|
||||||
if (nm == keyword)
|
|
||||||
goto kw_found2;
|
|
||||||
}
|
|
||||||
/* Slow fallback, just in case */
|
|
||||||
for (j = 0; j < total_args; j++) {
|
|
||||||
PyObject *nm = co_varnames[j];
|
|
||||||
int cmp = PyObject_RichCompareBool(
|
|
||||||
keyword, nm, Py_EQ);
|
|
||||||
if (cmp > 0)
|
|
||||||
goto kw_found2;
|
|
||||||
else if (cmp < 0)
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (j >= total_args && kwdict == NULL) {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"%U() got an unexpected "
|
|
||||||
"keyword argument '%S'",
|
|
||||||
co->co_name,
|
|
||||||
keyword);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (PyDict_SetItem(kwdict, keyword, value) == -1) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
kw_found2:
|
|
||||||
if (GETLOCAL(j) != NULL) {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"%U() got multiple "
|
|
||||||
"values for argument '%S'",
|
|
||||||
co->co_name,
|
|
||||||
keyword);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
Py_INCREF(value);
|
|
||||||
SETLOCAL(j, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check the number of positional arguments */
|
/* Check the number of positional arguments */
|
||||||
if (argcount > co->co_argcount && !(co->co_flags & CO_VARARGS)) {
|
if (argcount > co->co_argcount && !(co->co_flags & CO_VARARGS)) {
|
||||||
too_many_positional(co, argcount, defcount, fastlocals);
|
too_many_positional(co, argcount, defcount, fastlocals);
|
||||||
|
@ -4138,8 +4112,7 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
{
|
{
|
||||||
return _PyEval_EvalCodeWithName(_co, globals, locals,
|
return _PyEval_EvalCodeWithName(_co, globals, locals,
|
||||||
args, argcount,
|
args, argcount,
|
||||||
kws, kwcount,
|
kws, kws + 1, kwcount, 2,
|
||||||
NULL, NULL,
|
|
||||||
defs, defcount,
|
defs, defcount,
|
||||||
kwdefs, closure,
|
kwdefs, closure,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
@ -4923,8 +4896,9 @@ fast_function(PyObject *func, PyObject **stack,
|
||||||
}
|
}
|
||||||
return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
|
return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
|
||||||
stack, nargs,
|
stack, nargs,
|
||||||
NULL, 0,
|
nkwargs ? &PyTuple_GET_ITEM(kwnames, 0) : NULL,
|
||||||
kwnames, stack + nargs,
|
stack + nargs,
|
||||||
|
nkwargs, 1,
|
||||||
d, (int)nd, kwdefs,
|
d, (int)nd, kwdefs,
|
||||||
closure, name, qualname);
|
closure, name, qualname);
|
||||||
}
|
}
|
||||||
|
@ -5014,8 +4988,7 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
|
||||||
|
|
||||||
result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
|
result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
|
||||||
args, nargs,
|
args, nargs,
|
||||||
k, nk,
|
k, k + 1, nk, 2,
|
||||||
NULL, NULL,
|
|
||||||
d, nd, kwdefs,
|
d, nd, kwdefs,
|
||||||
closure, name, qualname);
|
closure, name, qualname);
|
||||||
Py_XDECREF(kwtuple);
|
Py_XDECREF(kwtuple);
|
||||||
|
|
|
@ -3503,7 +3503,7 @@ compiler_call_helper(struct compiler *c,
|
||||||
asdl_seq *keywords)
|
asdl_seq *keywords)
|
||||||
{
|
{
|
||||||
Py_ssize_t i, nseen, nelts, nkwelts;
|
Py_ssize_t i, nseen, nelts, nkwelts;
|
||||||
int musttupleunpack = 0, mustdictunpack = 0;
|
int mustdictunpack = 0;
|
||||||
|
|
||||||
/* the number of tuples and dictionaries on the stack */
|
/* the number of tuples and dictionaries on the stack */
|
||||||
Py_ssize_t nsubargs = 0, nsubkwargs = 0;
|
Py_ssize_t nsubargs = 0, nsubkwargs = 0;
|
||||||
|
@ -3532,7 +3532,6 @@ compiler_call_helper(struct compiler *c,
|
||||||
}
|
}
|
||||||
VISIT(c, expr, elt->v.Starred.value);
|
VISIT(c, expr, elt->v.Starred.value);
|
||||||
nsubargs++;
|
nsubargs++;
|
||||||
musttupleunpack = 1;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
VISIT(c, expr, elt);
|
VISIT(c, expr, elt);
|
||||||
|
@ -3541,13 +3540,13 @@ compiler_call_helper(struct compiler *c,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Same dance again for keyword arguments */
|
/* Same dance again for keyword arguments */
|
||||||
if (musttupleunpack || mustdictunpack) {
|
if (nsubargs || mustdictunpack) {
|
||||||
if (nseen) {
|
if (nseen) {
|
||||||
/* Pack up any trailing positional arguments. */
|
/* Pack up any trailing positional arguments. */
|
||||||
ADDOP_I(c, BUILD_TUPLE, nseen);
|
ADDOP_I(c, BUILD_TUPLE, nseen);
|
||||||
nsubargs++;
|
nsubargs++;
|
||||||
}
|
}
|
||||||
if (musttupleunpack || nsubargs > 1) {
|
if (nsubargs > 1) {
|
||||||
/* If we ended up with more than one stararg, we need
|
/* If we ended up with more than one stararg, we need
|
||||||
to concatenate them into a single sequence. */
|
to concatenate them into a single sequence. */
|
||||||
ADDOP_I(c, BUILD_TUPLE_UNPACK, nsubargs);
|
ADDOP_I(c, BUILD_TUPLE_UNPACK, nsubargs);
|
||||||
|
@ -3579,7 +3578,7 @@ compiler_call_helper(struct compiler *c,
|
||||||
return 0;
|
return 0;
|
||||||
nsubkwargs++;
|
nsubkwargs++;
|
||||||
}
|
}
|
||||||
if (mustdictunpack || nsubkwargs > 1) {
|
if (nsubkwargs > 1) {
|
||||||
/* Pack it all up */
|
/* Pack it all up */
|
||||||
ADDOP_I(c, BUILD_MAP_UNPACK_WITH_CALL, nsubkwargs);
|
ADDOP_I(c, BUILD_MAP_UNPACK_WITH_CALL, nsubkwargs);
|
||||||
}
|
}
|
||||||
|
|
2904
Python/importlib.h
2904
Python/importlib.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue