gh-122943: Rework support of var-positional parameter in Argument Clinic (GH-122945)

Move creation of a tuple for var-positional parameter out of
_PyArg_UnpackKeywordsWithVararg().
Merge _PyArg_UnpackKeywordsWithVararg() with _PyArg_UnpackKeywords().
Add a new parameter in _PyArg_UnpackKeywords().

The "parameters" and "converters" attributes of ParseArgsCodeGen no
longer contain the var-positional parameter. It is now available as the
"varpos" attribute. Optimize code generation for var-positional
parameter and reuse the same generating code for functions with and without
keyword parameters.

Add special converters for var-positional parameter. "tuple" represents it as
a Python tuple and "array" represents it as a continuous array of PyObject*.
"object" is a temporary alias of "tuple".
This commit is contained in:
Serhiy Storchaka 2024-11-07 23:40:03 +02:00 committed by GitHub
parent 09d6f5dc78
commit 1f777396f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 1597 additions and 662 deletions

View File

@ -76,7 +76,7 @@ PyAPI_FUNC(int) _PyArg_ParseStackAndKeywords(
...); ...);
// Export for 'math' shared extension // Export for 'math' shared extension
PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywords( PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywordsEx(
PyObject *const *args, PyObject *const *args,
Py_ssize_t nargs, Py_ssize_t nargs,
PyObject *kwargs, PyObject *kwargs,
@ -85,20 +85,19 @@ PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywords(
int minpos, int minpos,
int maxpos, int maxpos,
int minkw, int minkw,
int varpos,
PyObject **buf); PyObject **buf);
#define _PyArg_UnpackKeywords(args, nargs, kwargs, kwnames, parser, minpos, maxpos, minkw, buf) \ #define _PyArg_UnpackKeywords(args, nargs, kwargs, kwnames, parser, minpos, maxpos, minkw, buf) \
(((minkw) == 0 && (kwargs) == NULL && (kwnames) == NULL && \ (((minkw) == 0 && (kwargs) == NULL && (kwnames) == NULL && \
(minpos) <= (nargs) && (nargs) <= (maxpos) && (args) != NULL) ? (args) : \ (minpos) <= (nargs) && (nargs) <= (maxpos) && (args) != NULL) ? \
_PyArg_UnpackKeywords((args), (nargs), (kwargs), (kwnames), (parser), \ (args) : \
(minpos), (maxpos), (minkw), (buf))) _PyArg_UnpackKeywordsEx((args), (nargs), (kwargs), (kwnames), (parser), \
(minpos), (maxpos), (minkw), 0, (buf)))
// Export for '_testclinic' shared extension #define _PyArg_UnpackKeywordsWithVararg(args, nargs, kwargs, kwnames, parser, minpos, maxpos, minkw, buf) \
PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywordsWithVararg( (((minkw) == 0 && (kwargs) == NULL && (kwnames) == NULL && \
PyObject *const *args, Py_ssize_t nargs, (minpos) <= (nargs) && (args) != NULL) ? (args) : \
PyObject *kwargs, PyObject *kwnames, _PyArg_UnpackKeywordsEx((args), (nargs), (kwargs), (kwnames), (parser), \
struct _PyArg_Parser *parser, (minpos), (maxpos), (minkw), 1, (buf)))
int minpos, int maxpos, int minkw,
int vararg, PyObject **buf);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -20,7 +20,7 @@ extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *);
#define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item) #define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item)
extern PyObject *_PyTuple_FromArray(PyObject *const *, Py_ssize_t); PyAPI_FUNC(PyObject *)_PyTuple_FromArray(PyObject *const *, Py_ssize_t);
PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefSteal(const union _PyStackRef *, Py_ssize_t); PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefSteal(const union _PyStackRef *, Py_ssize_t);
PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t); PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);

View File

@ -4144,6 +4144,45 @@ PyDoc_STRVAR(test_vararg_and_posonly__doc__,
"--\n" "--\n"
"\n"); "\n");
#define TEST_VARARG_AND_POSONLY_METHODDEF \
{"test_vararg_and_posonly", _PyCFunction_CAST(test_vararg_and_posonly), METH_FASTCALL, test_vararg_and_posonly__doc__},
static PyObject *
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args);
static PyObject *
test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *a;
PyObject *__clinic_args = NULL;
if (!_PyArg_CheckPositional("test_vararg_and_posonly", nargs, 1, PY_SSIZE_T_MAX)) {
goto exit;
}
a = args[0];
__clinic_args = _PyTuple_FromArray(args + 1, nargs - 1);
if (__clinic_args == NULL) {
goto exit;
}
return_value = test_vararg_and_posonly_impl(module, a, __clinic_args);
exit:
/* Cleanup for args */
Py_XDECREF(__clinic_args);
return return_value;
}
static PyObject *
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args)
/*[clinic end generated code: output=0c11c475e240869e input=9cfa748bbff09877]*/
PyDoc_STRVAR(test_vararg_and_posonly__doc__,
"test_vararg_and_posonly($module, a, /, *args)\n"
"--\n"
"\n");
#define TEST_VARARG_AND_POSONLY_METHODDEF \ #define TEST_VARARG_AND_POSONLY_METHODDEF \
{"test_vararg_and_posonly", _PyCFunction_CAST(test_vararg_and_posonly), METH_FASTCALL, test_vararg_and_posonly__doc__}, {"test_vararg_and_posonly", _PyCFunction_CAST(test_vararg_and_posonly), METH_FASTCALL, test_vararg_and_posonly__doc__},
@ -4163,17 +4202,19 @@ test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t narg
goto exit; goto exit;
} }
a = args[0]; a = args[0];
__clinic_args = args + 1; __clinic_args = _PyTuple_FromArray(args + 1, nargs - 1);
if (__clinic_args == NULL) {
goto exit;
}
return_value = test_vararg_and_posonly_impl(module, a, nvararg, __clinic_args); return_value = test_vararg_and_posonly_impl(module, a, nvararg, __clinic_args);
exit: exit:
/* Cleanup for args */
Py_XDECREF(__clinic_args);
return return_value; return return_value;
} }
static PyObject *
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, Py_ssize_t nargs,
PyObject *const *args)
/*[clinic end generated code: output=dc2dd9483cc0459e input=9cfa748bbff09877]*/
/*[clinic input] /*[clinic input]
test_vararg test_vararg
@ -4224,26 +4265,34 @@ test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
.kwtuple = KWTUPLE, .kwtuple = KWTUPLE,
}; };
#undef KWTUPLE #undef KWTUPLE
PyObject *argsbuf[2]; PyObject *argsbuf[1];
PyObject * const *fastargs;
PyObject *a; PyObject *a;
PyObject *__clinic_args = NULL; PyObject *__clinic_args = NULL;
args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf); fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
if (!args) { if (!fastargs) {
goto exit;
}
a = fastargs[0];
__clinic_args = nargs > 1
? _PyTuple_FromArray(args + 1, nargs - 1)
: PyTuple_New(0);
if (__clinic_args == NULL) {
goto exit; goto exit;
} }
a = args[0];
__clinic_args = args[1];
return_value = test_vararg_impl(module, a, __clinic_args); return_value = test_vararg_impl(module, a, __clinic_args);
exit: exit:
/* Cleanup for args */
Py_XDECREF(__clinic_args); Py_XDECREF(__clinic_args);
return return_value; return return_value;
} }
static PyObject * static PyObject *
test_vararg_impl(PyObject *module, PyObject *a, PyObject *args) test_vararg_impl(PyObject *module, PyObject *a, PyObject *args)
/*[clinic end generated code: output=1411e464f358a7ba input=81d33815ad1bae6e]*/ /*[clinic end generated code: output=e7d7da6a7e008125 input=81d33815ad1bae6e]*/
/*[clinic input] /*[clinic input]
test_vararg_with_default test_vararg_with_default
@ -4296,37 +4345,45 @@ test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nar
.kwtuple = KWTUPLE, .kwtuple = KWTUPLE,
}; };
#undef KWTUPLE #undef KWTUPLE
PyObject *argsbuf[3]; PyObject *argsbuf[2];
PyObject * const *fastargs;
Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
PyObject *a; PyObject *a;
PyObject *__clinic_args = NULL; PyObject *__clinic_args = NULL;
int b = 0; int b = 0;
args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf); fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
if (!args) { if (!fastargs) {
goto exit; goto exit;
} }
a = args[0]; a = fastargs[0];
__clinic_args = args[1];
if (!noptargs) { if (!noptargs) {
goto skip_optional_kwonly; goto skip_optional_kwonly;
} }
b = PyObject_IsTrue(args[2]); b = PyObject_IsTrue(fastargs[1]);
if (b < 0) { if (b < 0) {
goto exit; goto exit;
} }
skip_optional_kwonly: skip_optional_kwonly:
__clinic_args = nargs > 1
? _PyTuple_FromArray(args + 1, nargs - 1)
: PyTuple_New(0);
if (__clinic_args == NULL) {
goto exit;
}
return_value = test_vararg_with_default_impl(module, a, __clinic_args, b); return_value = test_vararg_with_default_impl(module, a, __clinic_args, b);
exit: exit:
/* Cleanup for args */
Py_XDECREF(__clinic_args); Py_XDECREF(__clinic_args);
return return_value; return return_value;
} }
static PyObject * static PyObject *
test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args, test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args,
int b) int b)
/*[clinic end generated code: output=f09d4b917063ca41 input=6e110b54acd9b22d]*/ /*[clinic end generated code: output=46781f9920ecedcf input=6e110b54acd9b22d]*/
/*[clinic input] /*[clinic input]
test_vararg_with_only_defaults test_vararg_with_only_defaults
@ -4379,22 +4436,22 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize
.kwtuple = KWTUPLE, .kwtuple = KWTUPLE,
}; };
#undef KWTUPLE #undef KWTUPLE
PyObject *argsbuf[3]; PyObject *argsbuf[2];
PyObject * const *fastargs;
Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
PyObject *__clinic_args = NULL; PyObject *__clinic_args = NULL;
int b = 0; int b = 0;
PyObject *c = " "; PyObject *c = " ";
args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf);
if (!args) { if (!fastargs) {
goto exit; goto exit;
} }
__clinic_args = args[0];
if (!noptargs) { if (!noptargs) {
goto skip_optional_kwonly; goto skip_optional_kwonly;
} }
if (args[1]) { if (fastargs[0]) {
b = PyObject_IsTrue(args[1]); b = PyObject_IsTrue(fastargs[0]);
if (b < 0) { if (b < 0) {
goto exit; goto exit;
} }
@ -4402,19 +4459,25 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize
goto skip_optional_kwonly; goto skip_optional_kwonly;
} }
} }
c = args[2]; c = fastargs[1];
skip_optional_kwonly: skip_optional_kwonly:
__clinic_args = _PyTuple_FromArray(args, nargs);
if (__clinic_args == NULL) {
goto exit;
}
return_value = test_vararg_with_only_defaults_impl(module, __clinic_args, b, c); return_value = test_vararg_with_only_defaults_impl(module, __clinic_args, b, c);
exit: exit:
/* Cleanup for args */
Py_XDECREF(__clinic_args); Py_XDECREF(__clinic_args);
return return_value; return return_value;
} }
static PyObject * static PyObject *
test_vararg_with_only_defaults_impl(PyObject *module, PyObject *args, int b, test_vararg_with_only_defaults_impl(PyObject *module, PyObject *args, int b,
PyObject *c) PyObject *c)
/*[clinic end generated code: output=cc6590b8805d5433 input=fa56a709a035666e]*/ /*[clinic end generated code: output=d03daf5067039c03 input=fa56a709a035666e]*/
/*[clinic input] /*[clinic input]
test_paramname_module test_paramname_module
@ -4926,6 +4989,41 @@ PyDoc_STRVAR(Test___init____doc__,
"\n" "\n"
"Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE."); "Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE.");
static int
Test___init___impl(TestObj *self, PyObject *args);
static int
Test___init__(PyObject *self, PyObject *args, PyObject *kwargs)
{
int return_value = -1;
PyTypeObject *base_tp = TestType;
PyObject *__clinic_args = NULL;
if ((Py_IS_TYPE(self, base_tp) ||
Py_TYPE(self)->tp_new == base_tp->tp_new) &&
!_PyArg_NoKeywords("Test", kwargs)) {
goto exit;
}
__clinic_args = Py_NewRef(args);
return_value = Test___init___impl((TestObj *)self, __clinic_args);
exit:
/* Cleanup for args */
Py_XDECREF(__clinic_args);
return return_value;
}
static int
Test___init___impl(TestObj *self, PyObject *args)
/*[clinic end generated code: output=f172425cec373cd6 input=2a8bd0033c9ac772]*/
PyDoc_STRVAR(Test___init____doc__,
"Test(*args)\n"
"--\n"
"\n"
"Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE.");
static int static int
Test___init___impl(TestObj *self, Py_ssize_t nargs, PyObject *const *args); Test___init___impl(TestObj *self, Py_ssize_t nargs, PyObject *const *args);
@ -4941,19 +5039,16 @@ Test___init__(PyObject *self, PyObject *args, PyObject *kwargs)
!_PyArg_NoKeywords("Test", kwargs)) { !_PyArg_NoKeywords("Test", kwargs)) {
goto exit; goto exit;
} }
if (!_PyArg_CheckPositional("Test", PyTuple_GET_SIZE(args), 0, PY_SSIZE_T_MAX)) { __clinic_args = Py_NewRef(args);
goto exit;
}
__clinic_args = _PyTuple_CAST(args)->ob_item;
return_value = Test___init___impl((TestObj *)self, nvararg, __clinic_args); return_value = Test___init___impl((TestObj *)self, nvararg, __clinic_args);
exit: exit:
/* Cleanup for args */
Py_XDECREF(__clinic_args);
return return_value; return return_value;
} }
static int
Test___init___impl(TestObj *self, Py_ssize_t nargs, PyObject *const *args)
/*[clinic end generated code: output=6a64b417c9080a73 input=2a8bd0033c9ac772]*/
/*[clinic input] /*[clinic input]
@ -4970,6 +5065,40 @@ PyDoc_STRVAR(Test__doc__,
"\n" "\n"
"Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE."); "Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE.");
static PyObject *
Test_impl(PyTypeObject *type, PyObject *args);
static PyObject *
Test(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
PyObject *return_value = NULL;
PyTypeObject *base_tp = TestType;
PyObject *__clinic_args = NULL;
if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
!_PyArg_NoKeywords("Test", kwargs)) {
goto exit;
}
__clinic_args = Py_NewRef(args);
return_value = Test_impl(type, __clinic_args);
exit:
/* Cleanup for args */
Py_XDECREF(__clinic_args);
return return_value;
}
static PyObject *
Test_impl(PyTypeObject *type, PyObject *args)
/*[clinic end generated code: output=ee1e8892a67abd4a input=70ad829df3dd9b84]*/
PyDoc_STRVAR(Test__doc__,
"Test(*args)\n"
"--\n"
"\n"
"Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE.");
static PyObject * static PyObject *
Test_impl(PyTypeObject *type, Py_ssize_t nargs, PyObject *const *args); Test_impl(PyTypeObject *type, Py_ssize_t nargs, PyObject *const *args);
@ -4984,19 +5113,16 @@ Test(PyTypeObject *type, PyObject *args, PyObject *kwargs)
!_PyArg_NoKeywords("Test", kwargs)) { !_PyArg_NoKeywords("Test", kwargs)) {
goto exit; goto exit;
} }
if (!_PyArg_CheckPositional("Test", PyTuple_GET_SIZE(args), 0, PY_SSIZE_T_MAX)) { __clinic_args = Py_NewRef(args);
goto exit;
}
__clinic_args = _PyTuple_CAST(args)->ob_item;
return_value = Test_impl(type, nvararg, __clinic_args); return_value = Test_impl(type, nvararg, __clinic_args);
exit: exit:
/* Cleanup for args */
Py_XDECREF(__clinic_args);
return return_value; return return_value;
} }
static PyObject *
Test_impl(PyTypeObject *type, Py_ssize_t nargs, PyObject *const *args)
/*[clinic end generated code: output=bf22f942407383a5 input=70ad829df3dd9b84]*/
/*[clinic input] /*[clinic input]

View File

@ -33,6 +33,15 @@ with test_tools.imports_under_tool('clinic'):
from libclinic.cli import parse_file, Clinic from libclinic.cli import parse_file, Clinic
def repeat_fn(*functions):
def wrapper(test):
def wrapped(self):
for fn in functions:
with self.subTest(fn=fn):
test(self, fn)
return wrapped
return wrapper
def _make_clinic(*, filename='clinic_tests', limited_capi=False): def _make_clinic(*, filename='clinic_tests', limited_capi=False):
clang = CLanguage(filename) clang = CLanguage(filename)
c = Clinic(clang, filename=filename, limited_capi=limited_capi) c = Clinic(clang, filename=filename, limited_capi=limited_capi)
@ -3378,30 +3387,53 @@ class ClinicFunctionalTest(unittest.TestCase):
ac_tester.keyword_only_parameter(1) ac_tester.keyword_only_parameter(1)
self.assertEqual(ac_tester.keyword_only_parameter(a=1), (1,)) self.assertEqual(ac_tester.keyword_only_parameter(a=1), (1,))
def test_varpos(self): if ac_tester is not None:
@repeat_fn(ac_tester.varpos,
ac_tester.varpos_array,
ac_tester.TestClass.varpos_no_fastcall,
ac_tester.TestClass.varpos_array_no_fastcall)
def test_varpos(self, fn):
# fn(*args) # fn(*args)
fn = ac_tester.varpos self.assertEqual(fn(), ())
self.assertEqual(fn(), ((),)) self.assertEqual(fn(1, 2), (1, 2))
self.assertEqual(fn(1, 2), ((1, 2),))
def test_posonly_varpos(self): @repeat_fn(ac_tester.posonly_varpos,
ac_tester.posonly_varpos_array,
ac_tester.TestClass.posonly_varpos_no_fastcall,
ac_tester.TestClass.posonly_varpos_array_no_fastcall)
def test_posonly_varpos(self, fn):
# fn(a, b, /, *args) # fn(a, b, /, *args)
fn = ac_tester.posonly_varpos
self.assertRaises(TypeError, fn) self.assertRaises(TypeError, fn)
self.assertRaises(TypeError, fn, 1) self.assertRaises(TypeError, fn, 1)
self.assertRaises(TypeError, fn, 1, b=2) self.assertRaises(TypeError, fn, 1, b=2)
self.assertEqual(fn(1, 2), (1, 2, ())) self.assertEqual(fn(1, 2), (1, 2, ()))
self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4))) self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4)))
def test_posonly_poskw_varpos(self): @repeat_fn(ac_tester.posonly_req_opt_varpos,
ac_tester.posonly_req_opt_varpos_array,
ac_tester.TestClass.posonly_req_opt_varpos_no_fastcall,
ac_tester.TestClass.posonly_req_opt_varpos_array_no_fastcall)
def test_posonly_req_opt_varpos(self, fn):
# fn(a, b=False, /, *args)
self.assertRaises(TypeError, fn)
self.assertRaises(TypeError, fn, a=1)
self.assertEqual(fn(1), (1, False, ()))
self.assertEqual(fn(1, 2), (1, 2, ()))
self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4)))
@repeat_fn(ac_tester.posonly_poskw_varpos,
ac_tester.posonly_poskw_varpos_array,
ac_tester.TestClass.posonly_poskw_varpos_no_fastcall,
ac_tester.TestClass.posonly_poskw_varpos_array_no_fastcall)
def test_posonly_poskw_varpos(self, fn):
# fn(a, /, b, *args) # fn(a, /, b, *args)
fn = ac_tester.posonly_poskw_varpos
self.assertRaises(TypeError, fn) self.assertRaises(TypeError, fn)
self.assertEqual(fn(1, 2), (1, 2, ())) self.assertEqual(fn(1, 2), (1, 2, ()))
self.assertEqual(fn(1, b=2), (1, 2, ())) self.assertEqual(fn(1, b=2), (1, 2, ()))
self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4))) self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4)))
self.assertRaises(TypeError, fn, b=4) self.assertRaises(TypeError, fn, b=4)
self.assertRaises(TypeError, fn, 1, 2, 3, b=4) errmsg = re.escape("given by name ('b') and position (2)")
self.assertRaisesRegex(TypeError, errmsg, fn, 1, 2, 3, b=4)
def test_poskw_varpos(self): def test_poskw_varpos(self):
# fn(a, *args) # fn(a, *args)
@ -3409,7 +3441,8 @@ class ClinicFunctionalTest(unittest.TestCase):
self.assertRaises(TypeError, fn) self.assertRaises(TypeError, fn)
self.assertRaises(TypeError, fn, 1, b=2) self.assertRaises(TypeError, fn, 1, b=2)
self.assertEqual(fn(a=1), (1, ())) self.assertEqual(fn(a=1), (1, ()))
self.assertRaises(TypeError, fn, 1, a=2) errmsg = re.escape("given by name ('a') and position (1)")
self.assertRaisesRegex(TypeError, errmsg, fn, 1, a=2)
self.assertEqual(fn(1), (1, ())) self.assertEqual(fn(1), (1, ()))
self.assertEqual(fn(1, 2, 3, 4), (1, (2, 3, 4))) self.assertEqual(fn(1, 2, 3, 4), (1, (2, 3, 4)))
@ -3417,7 +3450,8 @@ class ClinicFunctionalTest(unittest.TestCase):
# fn(a, *args, b=False) # fn(a, *args, b=False)
fn = ac_tester.poskw_varpos_kwonly_opt fn = ac_tester.poskw_varpos_kwonly_opt
self.assertRaises(TypeError, fn) self.assertRaises(TypeError, fn)
self.assertRaises(TypeError, fn, 1, a=2) errmsg = re.escape("given by name ('a') and position (1)")
self.assertRaisesRegex(TypeError, errmsg, fn, 1, a=2)
self.assertEqual(fn(1, b=2), (1, (), True)) self.assertEqual(fn(1, b=2), (1, (), True))
self.assertEqual(fn(1, 2, 3, 4), (1, (2, 3, 4), False)) self.assertEqual(fn(1, 2, 3, 4), (1, (2, 3, 4), False))
self.assertEqual(fn(1, 2, 3, 4, b=5), (1, (2, 3, 4), True)) self.assertEqual(fn(1, 2, 3, 4, b=5), (1, (2, 3, 4), True))
@ -3428,7 +3462,8 @@ class ClinicFunctionalTest(unittest.TestCase):
# fn(a, *args, b=False, c=False) # fn(a, *args, b=False, c=False)
fn = ac_tester.poskw_varpos_kwonly_opt2 fn = ac_tester.poskw_varpos_kwonly_opt2
self.assertRaises(TypeError, fn) self.assertRaises(TypeError, fn)
self.assertRaises(TypeError, fn, 1, a=2) errmsg = re.escape("given by name ('a') and position (1)")
self.assertRaisesRegex(TypeError, errmsg, fn, 1, a=2)
self.assertEqual(fn(1, b=2), (1, (), 2, False)) self.assertEqual(fn(1, b=2), (1, (), 2, False))
self.assertEqual(fn(1, b=2, c=3), (1, (), 2, 3)) self.assertEqual(fn(1, b=2, c=3), (1, (), 2, 3))
self.assertEqual(fn(1, 2, 3), (1, (2, 3), False, False)) self.assertEqual(fn(1, 2, 3), (1, (2, 3), False, False))
@ -3490,9 +3525,10 @@ class ClinicFunctionalTest(unittest.TestCase):
self.assertEqual(fn(covariant=True, name='a'), ('a', (), True)) self.assertEqual(fn(covariant=True, name='a'), ('a', (), True))
self.assertRaises(TypeError, fn, covariant=True) self.assertRaises(TypeError, fn, covariant=True)
self.assertRaises(TypeError, fn, 1, name='a') errmsg = re.escape("given by name ('name') and position (1)")
self.assertRaises(TypeError, fn, 1, 2, 3, name='a', covariant=True) self.assertRaisesRegex(TypeError, errmsg, fn, 1, name='a')
self.assertRaises(TypeError, fn, 1, 2, 3, covariant=True, name='a') self.assertRaisesRegex(TypeError, errmsg, fn, 1, 2, 3, name='a', covariant=True)
self.assertRaisesRegex(TypeError, errmsg, fn, 1, 2, 3, covariant=True, name='a')
def test_cloned_func_exception_message(self): def test_cloned_func_exception_message(self):
incorrect_arg = -1 # f1() and f2() accept a single str incorrect_arg = -1 # f1() and f2() accept a single str
@ -3568,14 +3604,15 @@ class ClinicFunctionalTest(unittest.TestCase):
cls = ac_tester.TestClass cls = ac_tester.TestClass
obj = cls() obj = cls()
fn = obj.defclass_posonly_varpos fn = obj.defclass_posonly_varpos
self.assertRaises(TypeError, fn) errmsg = 'takes at least 2 positional arguments'
self.assertRaises(TypeError, fn, 1) self.assertRaisesRegex(TypeError, errmsg, fn)
self.assertRaisesRegex(TypeError, errmsg, fn, 1)
self.assertEqual(fn(1, 2), (cls, 1, 2, ())) self.assertEqual(fn(1, 2), (cls, 1, 2, ()))
self.assertEqual(fn(1, 2, 3, 4), (cls, 1, 2, (3, 4))) self.assertEqual(fn(1, 2, 3, 4), (cls, 1, 2, (3, 4)))
fn = cls.defclass_posonly_varpos fn = cls.defclass_posonly_varpos
self.assertRaises(TypeError, fn) self.assertRaises(TypeError, fn)
self.assertRaises(TypeError, fn, obj) self.assertRaisesRegex(TypeError, errmsg, fn, obj)
self.assertRaises(TypeError, fn, obj, 1) self.assertRaisesRegex(TypeError, errmsg, fn, obj, 1)
self.assertEqual(fn(obj, 1, 2), (cls, 1, 2, ())) self.assertEqual(fn(obj, 1, 2), (cls, 1, 2, ()))
self.assertEqual(fn(obj, 1, 2, 3, 4), (cls, 1, 2, (3, 4))) self.assertEqual(fn(obj, 1, 2, 3, 4), (cls, 1, 2, (3, 4)))

View File

@ -59,19 +59,20 @@ pack_arguments_newref(int argc, ...)
} }
static PyObject * static PyObject *
pack_varargs_to_tuple(Py_ssize_t varargssize, PyObject *const *args) pack_arguments_2pos_varpos(PyObject *a, PyObject *b,
PyObject * const *args, Py_ssize_t args_length)
/*[clinic end generated code: output=267032f41bd039cc input=86ee3064b7853e86]*/
{ {
assert(!PyErr_Occurred()); PyObject *tuple = _PyTuple_FromArray(args, args_length);
PyObject *tuple = PyTuple_New(varargssize); if (tuple == NULL) {
if (!tuple) {
return NULL; return NULL;
} }
for (Py_ssize_t i = 0; i < varargssize; i++) { PyObject *result = pack_arguments_newref(3, a, b, tuple);
PyTuple_SET_ITEM(tuple, i, Py_NewRef(args[i])); Py_DECREF(tuple);
} return result;
return tuple;
} }
/* Pack arguments to a tuple. /* Pack arguments to a tuple.
* `wrapper` is function which converts primitive type to PyObject. * `wrapper` is function which converts primitive type to PyObject.
* `arg_type` is type that arguments should be converted to before wrapped. */ * `arg_type` is type that arguments should be converted to before wrapped. */
@ -984,16 +985,10 @@ varpos
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
varpos_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args) varpos_impl(PyObject *module, PyObject *args)
/*[clinic end generated code: output=b65096f423fb5dcc input=f87cd674145d394c]*/ /*[clinic end generated code: output=7b0b9545872bdca4 input=f87cd674145d394c]*/
{ {
PyObject *vararg_tuple = pack_varargs_to_tuple(nargs, args); return Py_NewRef(args);
if (!vararg_tuple) {
return NULL;
}
PyObject *result = pack_arguments_newref(1, vararg_tuple);
Py_DECREF(vararg_tuple);
return result;
} }
@ -1009,16 +1004,29 @@ posonly_varpos
static PyObject * static PyObject *
posonly_varpos_impl(PyObject *module, PyObject *a, PyObject *b, posonly_varpos_impl(PyObject *module, PyObject *a, PyObject *b,
Py_ssize_t nargs, PyObject *const *args) PyObject *args)
/*[clinic end generated code: output=d10d43d86d117ab3 input=c9fd7895cfbaabba]*/ /*[clinic end generated code: output=5dae5eb2a0d623cd input=c9fd7895cfbaabba]*/
{ {
PyObject *vararg_tuple = pack_varargs_to_tuple(nargs, args); return pack_arguments_newref(3, a, b, args);
if (!vararg_tuple) { }
return NULL;
}
PyObject *result = pack_arguments_newref(3, a, b, vararg_tuple); /*[clinic input]
Py_DECREF(vararg_tuple); posonly_req_opt_varpos
return result;
a: object
b: object = False
/
*args: object
[clinic start generated code]*/
static PyObject *
posonly_req_opt_varpos_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *args)
/*[clinic end generated code: output=67f82f90838e166a input=a49bd64740171e1c]*/
{
return pack_arguments_newref(3, a, b, args);
} }
@ -1130,6 +1138,81 @@ varpos_kwonly_req_opt_impl(PyObject *module, PyObject *args, PyObject *a,
} }
/*[clinic input]
varpos_array
*args: array
[clinic start generated code]*/
static PyObject *
varpos_array_impl(PyObject *module, PyObject * const *args,
Py_ssize_t args_length)
/*[clinic end generated code: output=a25f42f39c9b13ad input=97b8bdcf87e019c7]*/
{
return _PyTuple_FromArray(args, args_length);
}
/*[clinic input]
posonly_varpos_array
a: object
b: object
/
*args: array
[clinic start generated code]*/
static PyObject *
posonly_varpos_array_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject * const *args, Py_ssize_t args_length)
/*[clinic end generated code: output=267032f41bd039cc input=86ee3064b7853e86]*/
{
return pack_arguments_2pos_varpos(a, b, args, args_length);
}
/*[clinic input]
posonly_req_opt_varpos_array
a: object
b: object = False
/
*args: array
[clinic start generated code]*/
static PyObject *
posonly_req_opt_varpos_array_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject * const *args,
Py_ssize_t args_length)
/*[clinic end generated code: output=f2f93c77ead93699 input=b01d7728164fd93e]*/
{
return pack_arguments_2pos_varpos(a, b, args, args_length);
}
/*[clinic input]
posonly_poskw_varpos_array
a: object
/
b: object
*args: array
[clinic start generated code]*/
static PyObject *
posonly_poskw_varpos_array_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject * const *args,
Py_ssize_t args_length)
/*[clinic end generated code: output=155811a8b2d65a12 input=5fb08cdc6afb9d7c]*/
{
return pack_arguments_2pos_varpos(a, b, args, args_length);
}
/*[clinic input] /*[clinic input]
gh_32092_oob gh_32092_oob
@ -1183,9 +1266,8 @@ Proof-of-concept of GH-99233 refcount error bug.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
gh_99233_refcount_impl(PyObject *module, Py_ssize_t nargs, gh_99233_refcount_impl(PyObject *module, PyObject *args)
PyObject *const *args) /*[clinic end generated code: output=585855abfbca9a7f input=eecfdc2092d90dc3]*/
/*[clinic end generated code: output=b570007e61e5c670 input=eecfdc2092d90dc3]*/
{ {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -1295,9 +1377,9 @@ clone_with_conv_f2_impl(PyObject *module, custom_t path)
/*[clinic input] /*[clinic input]
class _testclinic.TestClass "PyObject *" "PyObject" class _testclinic.TestClass "PyObject *" "&PyBaseObject_Type"
[clinic start generated code]*/ [clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=668a591c65bec947]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=c991635bb3c91f1a]*/
/*[clinic input] /*[clinic input]
_testclinic.TestClass.get_defining_class _testclinic.TestClass.get_defining_class
@ -1360,11 +1442,192 @@ _testclinic_TestClass_defclass_posonly_varpos_impl(PyObject *self,
return pack_arguments_newref(4, cls, a, b, args); return pack_arguments_newref(4, cls, a, b, args);
} }
/*[clinic input]
@classmethod
_testclinic.TestClass.__new__ as varpos_no_fastcall
*args: object
[clinic start generated code]*/
static PyObject *
varpos_no_fastcall_impl(PyTypeObject *type, PyObject *args)
/*[clinic end generated code: output=04e94f2898bb2dde input=b0447ebab3e81001]*/
{
return Py_NewRef(args);
}
/*[clinic input]
@classmethod
_testclinic.TestClass.__new__ as posonly_varpos_no_fastcall
a: object
b: object
/
*args: object
[clinic start generated code]*/
static PyObject *
posonly_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a, PyObject *b,
PyObject *args)
/*[clinic end generated code: output=b0a0425719f69f5a input=d2ec37a06b3c2389]*/
{
return pack_arguments_newref(3, a, b, args);
}
/*[clinic input]
@classmethod
_testclinic.TestClass.__new__ as posonly_req_opt_varpos_no_fastcall
a: object
b: object = False
/
*args: object
[clinic start generated code]*/
static PyObject *
posonly_req_opt_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a,
PyObject *b, PyObject *args)
/*[clinic end generated code: output=3c44915b1a554e2d input=e9e74686a5e6a06d]*/
{
return pack_arguments_newref(3, a, b, args);
}
/*[clinic input]
@classmethod
_testclinic.TestClass.__new__ as posonly_poskw_varpos_no_fastcall
a: object
/
b: object
*args: object
[clinic start generated code]*/
static PyObject *
posonly_poskw_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a,
PyObject *b, PyObject *args)
/*[clinic end generated code: output=6ad74bed4bdc7f96 input=fa931c38184213aa]*/
{
return pack_arguments_newref(3, a, b, args);
}
/*[clinic input]
@classmethod
_testclinic.TestClass.__new__ as varpos_array_no_fastcall
*args: array
[clinic start generated code]*/
static PyObject *
varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject * const *args,
Py_ssize_t args_length)
/*[clinic end generated code: output=f99d984346c60d42 input=368d8eea6de48c12]*/
{
return _PyTuple_FromArray(args, args_length);
}
/*[clinic input]
@classmethod
_testclinic.TestClass.__new__ as posonly_varpos_array_no_fastcall
a: object
b: object
/
*args: array
[clinic start generated code]*/
static PyObject *
posonly_varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject *a,
PyObject *b, PyObject * const *args,
Py_ssize_t args_length)
/*[clinic end generated code: output=1eec4da1fb5b5978 input=7330c8d819a23548]*/
{
return pack_arguments_2pos_varpos(a, b, args, args_length);
}
/*[clinic input]
@classmethod
_testclinic.TestClass.__new__ as posonly_req_opt_varpos_array_no_fastcall
a: object
b: object = False
/
*args: array
[clinic start generated code]*/
static PyObject *
posonly_req_opt_varpos_array_no_fastcall_impl(PyTypeObject *type,
PyObject *a, PyObject *b,
PyObject * const *args,
Py_ssize_t args_length)
/*[clinic end generated code: output=88041c2176135218 input=7f5fd34ee5f9e0bf]*/
{
return pack_arguments_2pos_varpos(a, b, args, args_length);
}
/*[clinic input]
@classmethod
_testclinic.TestClass.__new__ as posonly_poskw_varpos_array_no_fastcall
a: object
/
b: object
*args: array
[clinic start generated code]*/
static PyObject *
posonly_poskw_varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject *a,
PyObject *b,
PyObject * const *args,
Py_ssize_t args_length)
/*[clinic end generated code: output=70eda18c3667681e input=2b0fcd7bd9bb865c]*/
{
return pack_arguments_2pos_varpos(a, b, args, args_length);
}
static struct PyMethodDef test_class_methods[] = { static struct PyMethodDef test_class_methods[] = {
_TESTCLINIC_TESTCLASS_GET_DEFINING_CLASS_METHODDEF _TESTCLINIC_TESTCLASS_GET_DEFINING_CLASS_METHODDEF
_TESTCLINIC_TESTCLASS_GET_DEFINING_CLASS_ARG_METHODDEF _TESTCLINIC_TESTCLASS_GET_DEFINING_CLASS_ARG_METHODDEF
_TESTCLINIC_TESTCLASS_DEFCLASS_VARPOS_METHODDEF _TESTCLINIC_TESTCLASS_DEFCLASS_VARPOS_METHODDEF
_TESTCLINIC_TESTCLASS_DEFCLASS_POSONLY_VARPOS_METHODDEF _TESTCLINIC_TESTCLASS_DEFCLASS_POSONLY_VARPOS_METHODDEF
{"varpos_no_fastcall", _PyCFunction_CAST(varpos_no_fastcall),
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
{"posonly_varpos_no_fastcall", _PyCFunction_CAST(posonly_varpos_no_fastcall),
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
{"posonly_req_opt_varpos_no_fastcall", _PyCFunction_CAST(posonly_req_opt_varpos_no_fastcall),
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
{"posonly_poskw_varpos_no_fastcall", _PyCFunction_CAST(posonly_poskw_varpos_no_fastcall),
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
{"varpos_array_no_fastcall",
_PyCFunction_CAST(varpos_array_no_fastcall),
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
{"posonly_varpos_array_no_fastcall",
_PyCFunction_CAST(posonly_varpos_array_no_fastcall),
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
{"posonly_req_opt_varpos_array_no_fastcall",
_PyCFunction_CAST(posonly_req_opt_varpos_array_no_fastcall),
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
{"posonly_poskw_varpos_array_no_fastcall",
_PyCFunction_CAST(posonly_poskw_varpos_array_no_fastcall),
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
{NULL, NULL} {NULL, NULL}
}; };
@ -2023,12 +2286,19 @@ static PyMethodDef tester_methods[] = {
VARPOS_METHODDEF VARPOS_METHODDEF
POSONLY_VARPOS_METHODDEF POSONLY_VARPOS_METHODDEF
POSONLY_REQ_OPT_VARPOS_METHODDEF
POSONLY_POSKW_VARPOS_METHODDEF POSONLY_POSKW_VARPOS_METHODDEF
POSKW_VARPOS_METHODDEF POSKW_VARPOS_METHODDEF
POSKW_VARPOS_KWONLY_OPT_METHODDEF POSKW_VARPOS_KWONLY_OPT_METHODDEF
POSKW_VARPOS_KWONLY_OPT2_METHODDEF POSKW_VARPOS_KWONLY_OPT2_METHODDEF
VARPOS_KWONLY_OPT_METHODDEF VARPOS_KWONLY_OPT_METHODDEF
VARPOS_KWONLY_REQ_OPT_METHODDEF VARPOS_KWONLY_REQ_OPT_METHODDEF
VARPOS_ARRAY_METHODDEF
POSONLY_VARPOS_ARRAY_METHODDEF
POSONLY_REQ_OPT_VARPOS_ARRAY_METHODDEF
POSONLY_POSKW_VARPOS_ARRAY_METHODDEF
GH_32092_OOB_METHODDEF GH_32092_OOB_METHODDEF
GH_32092_KW_PASS_METHODDEF GH_32092_KW_PASS_METHODDEF
GH_99233_REFCOUNT_METHODDEF GH_99233_REFCOUNT_METHODDEF

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@ preserve
#include "pycore_long.h" // _PyLong_UnsignedShort_Converter() #include "pycore_long.h" // _PyLong_UnsignedShort_Converter()
#include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_modsupport.h" // _PyArg_CheckPositional()
#include "pycore_runtime.h" // _Py_ID() #include "pycore_runtime.h" // _Py_ID()
#include "pycore_tuple.h" // _PyTuple_FromArray()
PyDoc_STRVAR(depr_star_new__doc__, PyDoc_STRVAR(depr_star_new__doc__,
"DeprStarNew(a=None)\n" "DeprStarNew(a=None)\n"
@ -2393,4 +2394,4 @@ depr_multi(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=ca6da2c7137554be input=a9049054013a1b77]*/ /*[clinic end generated code: output=5dda27c80df7351e input=a9049054013a1b77]*/

View File

@ -8,6 +8,7 @@ preserve
#endif #endif
#include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t() #include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t()
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
#include "pycore_tuple.h" // _PyTuple_FromArray()
PyDoc_STRVAR(gc_enable__doc__, PyDoc_STRVAR(gc_enable__doc__,
"enable($module, /)\n" "enable($module, /)\n"
@ -312,23 +313,24 @@ PyDoc_STRVAR(gc_get_referrers__doc__,
{"get_referrers", _PyCFunction_CAST(gc_get_referrers), METH_FASTCALL, gc_get_referrers__doc__}, {"get_referrers", _PyCFunction_CAST(gc_get_referrers), METH_FASTCALL, gc_get_referrers__doc__},
static PyObject * static PyObject *
gc_get_referrers_impl(PyObject *module, Py_ssize_t nargs, gc_get_referrers_impl(PyObject *module, PyObject *objs);
PyObject *const *args);
static PyObject * static PyObject *
gc_get_referrers(PyObject *module, PyObject *const *args, Py_ssize_t nargs) gc_get_referrers(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
Py_ssize_t nvararg = nargs - 0; PyObject *objs = NULL;
PyObject *const *__clinic_args = NULL;
if (!_PyArg_CheckPositional("get_referrers", nargs, 0, PY_SSIZE_T_MAX)) { objs = _PyTuple_FromArray(args, nargs);
if (objs == NULL) {
goto exit; goto exit;
} }
__clinic_args = args + 0; return_value = gc_get_referrers_impl(module, objs);
return_value = gc_get_referrers_impl(module, nvararg, __clinic_args);
exit: exit:
/* Cleanup for objs */
Py_XDECREF(objs);
return return_value; return return_value;
} }
@ -342,23 +344,24 @@ PyDoc_STRVAR(gc_get_referents__doc__,
{"get_referents", _PyCFunction_CAST(gc_get_referents), METH_FASTCALL, gc_get_referents__doc__}, {"get_referents", _PyCFunction_CAST(gc_get_referents), METH_FASTCALL, gc_get_referents__doc__},
static PyObject * static PyObject *
gc_get_referents_impl(PyObject *module, Py_ssize_t nargs, gc_get_referents_impl(PyObject *module, PyObject *objs);
PyObject *const *args);
static PyObject * static PyObject *
gc_get_referents(PyObject *module, PyObject *const *args, Py_ssize_t nargs) gc_get_referents(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
Py_ssize_t nvararg = nargs - 0; PyObject *objs = NULL;
PyObject *const *__clinic_args = NULL;
if (!_PyArg_CheckPositional("get_referents", nargs, 0, PY_SSIZE_T_MAX)) { objs = _PyTuple_FromArray(args, nargs);
if (objs == NULL) {
goto exit; goto exit;
} }
__clinic_args = args + 0; return_value = gc_get_referents_impl(module, objs);
return_value = gc_get_referents_impl(module, nvararg, __clinic_args);
exit: exit:
/* Cleanup for objs */
Py_XDECREF(objs);
return return_value; return return_value;
} }
@ -575,4 +578,4 @@ gc_get_freeze_count(PyObject *module, PyObject *Py_UNUSED(ignored))
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=f488a0d4d6bd3687 input=a9049054013a1b77]*/ /*[clinic end generated code: output=4f35875870da17c9 input=a9049054013a1b77]*/

View File

@ -18,22 +18,20 @@ PyDoc_STRVAR(math_gcd__doc__,
{"gcd", _PyCFunction_CAST(math_gcd), METH_FASTCALL, math_gcd__doc__}, {"gcd", _PyCFunction_CAST(math_gcd), METH_FASTCALL, math_gcd__doc__},
static PyObject * static PyObject *
math_gcd_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args); math_gcd_impl(PyObject *module, PyObject * const *args,
Py_ssize_t args_length);
static PyObject * static PyObject *
math_gcd(PyObject *module, PyObject *const *args, Py_ssize_t nargs) math_gcd(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
Py_ssize_t nvararg = nargs - 0; PyObject * const *__clinic_args;
PyObject *const *__clinic_args = NULL; Py_ssize_t args_length;
if (!_PyArg_CheckPositional("gcd", nargs, 0, PY_SSIZE_T_MAX)) { __clinic_args = args;
goto exit; args_length = nargs;
} return_value = math_gcd_impl(module, __clinic_args, args_length);
__clinic_args = args + 0;
return_value = math_gcd_impl(module, nvararg, __clinic_args);
exit:
return return_value; return return_value;
} }
@ -47,22 +45,20 @@ PyDoc_STRVAR(math_lcm__doc__,
{"lcm", _PyCFunction_CAST(math_lcm), METH_FASTCALL, math_lcm__doc__}, {"lcm", _PyCFunction_CAST(math_lcm), METH_FASTCALL, math_lcm__doc__},
static PyObject * static PyObject *
math_lcm_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args); math_lcm_impl(PyObject *module, PyObject * const *args,
Py_ssize_t args_length);
static PyObject * static PyObject *
math_lcm(PyObject *module, PyObject *const *args, Py_ssize_t nargs) math_lcm(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
Py_ssize_t nvararg = nargs - 0; PyObject * const *__clinic_args;
PyObject *const *__clinic_args = NULL; Py_ssize_t args_length;
if (!_PyArg_CheckPositional("lcm", nargs, 0, PY_SSIZE_T_MAX)) { __clinic_args = args;
goto exit; args_length = nargs;
} return_value = math_lcm_impl(module, __clinic_args, args_length);
__clinic_args = args + 0;
return_value = math_lcm_impl(module, nvararg, __clinic_args);
exit:
return return_value; return return_value;
} }
@ -430,22 +426,20 @@ PyDoc_STRVAR(math_hypot__doc__,
{"hypot", _PyCFunction_CAST(math_hypot), METH_FASTCALL, math_hypot__doc__}, {"hypot", _PyCFunction_CAST(math_hypot), METH_FASTCALL, math_hypot__doc__},
static PyObject * static PyObject *
math_hypot_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args); math_hypot_impl(PyObject *module, PyObject * const *args,
Py_ssize_t args_length);
static PyObject * static PyObject *
math_hypot(PyObject *module, PyObject *const *args, Py_ssize_t nargs) math_hypot(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
Py_ssize_t nvararg = nargs - 0; PyObject * const *__clinic_args;
PyObject *const *__clinic_args = NULL; Py_ssize_t args_length;
if (!_PyArg_CheckPositional("hypot", nargs, 0, PY_SSIZE_T_MAX)) { __clinic_args = args;
goto exit; args_length = nargs;
} return_value = math_hypot_impl(module, __clinic_args, args_length);
__clinic_args = args + 0;
return_value = math_hypot_impl(module, nvararg, __clinic_args);
exit:
return return_value; return return_value;
} }
@ -1109,4 +1103,4 @@ math_ulp(PyObject *module, PyObject *arg)
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=ff99a737c18d9210 input=a9049054013a1b77]*/ /*[clinic end generated code: output=cb506f61bc5ef862 input=a9049054013a1b77]*/

View File

@ -216,31 +216,21 @@ gc_get_count_impl(PyObject *module)
/*[clinic input] /*[clinic input]
gc.get_referrers gc.get_referrers
*objs as args: object *objs: tuple
Return the list of objects that directly refer to any of 'objs'. Return the list of objects that directly refer to any of 'objs'.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
gc_get_referrers_impl(PyObject *module, Py_ssize_t nargs, gc_get_referrers_impl(PyObject *module, PyObject *objs)
PyObject *const *args) /*[clinic end generated code: output=929d6dff26f609b9 input=9102be7ebee69ee3]*/
/*[clinic end generated code: output=1d44a7695ea25c40 input=bae96961b14a0922]*/
{ {
PyObject *varargs = _PyTuple_FromArray(args, nargs); if (PySys_Audit("gc.get_referrers", "(O)", objs) < 0) {
if (!varargs) {
return NULL;
}
if (PySys_Audit("gc.get_referrers", "(O)", varargs) < 0) {
Py_DECREF(varargs);
return NULL; return NULL;
} }
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
PyObject *result = _PyGC_GetReferrers(interp, varargs); return _PyGC_GetReferrers(interp, objs);
Py_DECREF(varargs);
return result;
} }
/* Append obj to list; return true if error (out of memory), false if OK. */ /* Append obj to list; return true if error (out of memory), false if OK. */
@ -274,43 +264,34 @@ append_referrents(PyObject *result, PyObject *args)
/*[clinic input] /*[clinic input]
gc.get_referents gc.get_referents
*objs as args: object *objs: tuple
Return the list of objects that are directly referred to by 'objs'. Return the list of objects that are directly referred to by 'objs'.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
gc_get_referents_impl(PyObject *module, Py_ssize_t nargs, gc_get_referents_impl(PyObject *module, PyObject *objs)
PyObject *const *args) /*[clinic end generated code: output=6dfde40cd1588e1d input=55c078a6d0248fe0]*/
/*[clinic end generated code: output=e459f3e8c0d19311 input=b3ceab0c34038cbf]*/
{ {
PyObject *varargs = _PyTuple_FromArray(args, nargs); if (PySys_Audit("gc.get_referents", "(O)", objs) < 0) {
if (!varargs) {
return NULL;
}
if (PySys_Audit("gc.get_referents", "(O)", varargs) < 0) {
Py_DECREF(varargs);
return NULL; return NULL;
} }
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
PyObject *result = PyList_New(0); PyObject *result = PyList_New(0);
if (result == NULL) { if (result == NULL) {
Py_DECREF(varargs);
return NULL; return NULL;
} }
// NOTE: stop the world is a no-op in default build // NOTE: stop the world is a no-op in default build
_PyEval_StopTheWorld(interp); _PyEval_StopTheWorld(interp);
int err = append_referrents(result, varargs); int err = append_referrents(result, objs);
_PyEval_StartTheWorld(interp); _PyEval_StartTheWorld(interp);
if (err < 0) { if (err < 0) {
Py_CLEAR(result); Py_CLEAR(result);
} }
Py_DECREF(varargs);
return result; return result;
} }

View File

@ -722,22 +722,23 @@ m_log10(double x)
/*[clinic input] /*[clinic input]
math.gcd math.gcd
*integers as args: object *integers as args: array
Greatest Common Divisor. Greatest Common Divisor.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
math_gcd_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args) math_gcd_impl(PyObject *module, PyObject * const *args,
/*[clinic end generated code: output=b57687fcf431c1b8 input=94e675b7ceeaf0c9]*/ Py_ssize_t args_length)
/*[clinic end generated code: output=a26c95907374ffb4 input=ded7f0ea3850c05c]*/
{ {
// Fast-path for the common case: gcd(int, int) // Fast-path for the common case: gcd(int, int)
if (nargs == 2 && PyLong_CheckExact(args[0]) && PyLong_CheckExact(args[1])) if (args_length == 2 && PyLong_CheckExact(args[0]) && PyLong_CheckExact(args[1]))
{ {
return _PyLong_GCD(args[0], args[1]); return _PyLong_GCD(args[0], args[1]);
} }
if (nargs == 0) { if (args_length == 0) {
return PyLong_FromLong(0); return PyLong_FromLong(0);
} }
@ -745,13 +746,13 @@ math_gcd_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args)
if (res == NULL) { if (res == NULL) {
return NULL; return NULL;
} }
if (nargs == 1) { if (args_length == 1) {
Py_SETREF(res, PyNumber_Absolute(res)); Py_SETREF(res, PyNumber_Absolute(res));
return res; return res;
} }
PyObject *one = _PyLong_GetOne(); // borrowed ref PyObject *one = _PyLong_GetOne(); // borrowed ref
for (Py_ssize_t i = 1; i < nargs; i++) { for (Py_ssize_t i = 1; i < args_length; i++) {
PyObject *x = _PyNumber_Index(args[i]); PyObject *x = _PyNumber_Index(args[i]);
if (x == NULL) { if (x == NULL) {
Py_DECREF(res); Py_DECREF(res);
@ -804,32 +805,33 @@ long_lcm(PyObject *a, PyObject *b)
/*[clinic input] /*[clinic input]
math.lcm math.lcm
*integers as args: object *integers as args: array
Least Common Multiple. Least Common Multiple.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
math_lcm_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args) math_lcm_impl(PyObject *module, PyObject * const *args,
/*[clinic end generated code: output=f3eff0c25e4d7030 input=e64c33e85f4c47c6]*/ Py_ssize_t args_length)
/*[clinic end generated code: output=c8a59a5c2e55c816 input=3e4f4b7cdf948a98]*/
{ {
PyObject *res, *x; PyObject *res, *x;
Py_ssize_t i; Py_ssize_t i;
if (nargs == 0) { if (args_length == 0) {
return PyLong_FromLong(1); return PyLong_FromLong(1);
} }
res = PyNumber_Index(args[0]); res = PyNumber_Index(args[0]);
if (res == NULL) { if (res == NULL) {
return NULL; return NULL;
} }
if (nargs == 1) { if (args_length == 1) {
Py_SETREF(res, PyNumber_Absolute(res)); Py_SETREF(res, PyNumber_Absolute(res));
return res; return res;
} }
PyObject *zero = _PyLong_GetZero(); // borrowed ref PyObject *zero = _PyLong_GetZero(); // borrowed ref
for (i = 1; i < nargs; i++) { for (i = 1; i < args_length; i++) {
x = PyNumber_Index(args[i]); x = PyNumber_Index(args[i]);
if (x == NULL) { if (x == NULL) {
Py_DECREF(res); Py_DECREF(res);
@ -2629,7 +2631,7 @@ math_dist_impl(PyObject *module, PyObject *p, PyObject *q)
/*[clinic input] /*[clinic input]
math.hypot math.hypot
*coordinates as args: object *coordinates as args: array
Multidimensional Euclidean distance from the origin to a point. Multidimensional Euclidean distance from the origin to a point.
@ -2646,8 +2648,9 @@ For example, the hypotenuse of a 3/4/5 right triangle is:
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
math_hypot_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args) math_hypot_impl(PyObject *module, PyObject * const *args,
/*[clinic end generated code: output=dcb6d4b7a1102ee1 input=5c0061a2d11235ed]*/ Py_ssize_t args_length)
/*[clinic end generated code: output=c9de404e24370068 input=1bceaf7d4fdcd9c2]*/
{ {
Py_ssize_t i; Py_ssize_t i;
PyObject *item; PyObject *item;
@ -2657,13 +2660,13 @@ math_hypot_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args)
double coord_on_stack[NUM_STACK_ELEMS]; double coord_on_stack[NUM_STACK_ELEMS];
double *coordinates = coord_on_stack; double *coordinates = coord_on_stack;
if (nargs > NUM_STACK_ELEMS) { if (args_length > NUM_STACK_ELEMS) {
coordinates = (double *) PyMem_Malloc(nargs * sizeof(double)); coordinates = (double *) PyMem_Malloc(args_length * sizeof(double));
if (coordinates == NULL) { if (coordinates == NULL) {
return PyErr_NoMemory(); return PyErr_NoMemory();
} }
} }
for (i = 0; i < nargs; i++) { for (i = 0; i < args_length; i++) {
item = args[i]; item = args[i];
ASSIGN_DOUBLE(x, item, error_exit); ASSIGN_DOUBLE(x, item, error_exit);
x = fabs(x); x = fabs(x);
@ -2673,7 +2676,7 @@ math_hypot_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args)
max = x; max = x;
} }
} }
result = vector_norm(nargs, coordinates, max, found_nan); result = vector_norm(args_length, coordinates, max, found_nan);
if (coordinates != coord_on_stack) { if (coordinates != coord_on_stack) {
PyMem_Free(coordinates); PyMem_Free(coordinates);
} }

View File

@ -3,7 +3,6 @@ preserve
[clinic start generated code]*/ [clinic start generated code]*/
#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
PyDoc_STRVAR(set_pop__doc__, PyDoc_STRVAR(set_pop__doc__,
"pop($self, /)\n" "pop($self, /)\n"
@ -41,22 +40,20 @@ PyDoc_STRVAR(set_update__doc__,
{"update", _PyCFunction_CAST(set_update), METH_FASTCALL, set_update__doc__}, {"update", _PyCFunction_CAST(set_update), METH_FASTCALL, set_update__doc__},
static PyObject * static PyObject *
set_update_impl(PySetObject *so, Py_ssize_t nargs, PyObject *const *args); set_update_impl(PySetObject *so, PyObject * const *others,
Py_ssize_t others_length);
static PyObject * static PyObject *
set_update(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) set_update(PySetObject *so, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
Py_ssize_t nvararg = nargs - 0; PyObject * const *others;
PyObject *const *__clinic_args = NULL; Py_ssize_t others_length;
if (!_PyArg_CheckPositional("update", nargs, 0, PY_SSIZE_T_MAX)) { others = args;
goto exit; others_length = nargs;
} return_value = set_update_impl(so, others, others_length);
__clinic_args = args + 0;
return_value = set_update_impl(so, nvararg, __clinic_args);
exit:
return return_value; return return_value;
} }
@ -142,22 +139,20 @@ PyDoc_STRVAR(set_union__doc__,
{"union", _PyCFunction_CAST(set_union), METH_FASTCALL, set_union__doc__}, {"union", _PyCFunction_CAST(set_union), METH_FASTCALL, set_union__doc__},
static PyObject * static PyObject *
set_union_impl(PySetObject *so, Py_ssize_t nargs, PyObject *const *args); set_union_impl(PySetObject *so, PyObject * const *others,
Py_ssize_t others_length);
static PyObject * static PyObject *
set_union(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) set_union(PySetObject *so, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
Py_ssize_t nvararg = nargs - 0; PyObject * const *others;
PyObject *const *__clinic_args = NULL; Py_ssize_t others_length;
if (!_PyArg_CheckPositional("union", nargs, 0, PY_SSIZE_T_MAX)) { others = args;
goto exit; others_length = nargs;
} return_value = set_union_impl(so, others, others_length);
__clinic_args = args + 0;
return_value = set_union_impl(so, nvararg, __clinic_args);
exit:
return return_value; return return_value;
} }
@ -171,23 +166,20 @@ PyDoc_STRVAR(set_intersection_multi__doc__,
{"intersection", _PyCFunction_CAST(set_intersection_multi), METH_FASTCALL, set_intersection_multi__doc__}, {"intersection", _PyCFunction_CAST(set_intersection_multi), METH_FASTCALL, set_intersection_multi__doc__},
static PyObject * static PyObject *
set_intersection_multi_impl(PySetObject *so, Py_ssize_t nargs, set_intersection_multi_impl(PySetObject *so, PyObject * const *others,
PyObject *const *args); Py_ssize_t others_length);
static PyObject * static PyObject *
set_intersection_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) set_intersection_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
Py_ssize_t nvararg = nargs - 0; PyObject * const *others;
PyObject *const *__clinic_args = NULL; Py_ssize_t others_length;
if (!_PyArg_CheckPositional("intersection", nargs, 0, PY_SSIZE_T_MAX)) { others = args;
goto exit; others_length = nargs;
} return_value = set_intersection_multi_impl(so, others, others_length);
__clinic_args = args + 0;
return_value = set_intersection_multi_impl(so, nvararg, __clinic_args);
exit:
return return_value; return return_value;
} }
@ -201,23 +193,20 @@ PyDoc_STRVAR(set_intersection_update_multi__doc__,
{"intersection_update", _PyCFunction_CAST(set_intersection_update_multi), METH_FASTCALL, set_intersection_update_multi__doc__}, {"intersection_update", _PyCFunction_CAST(set_intersection_update_multi), METH_FASTCALL, set_intersection_update_multi__doc__},
static PyObject * static PyObject *
set_intersection_update_multi_impl(PySetObject *so, Py_ssize_t nargs, set_intersection_update_multi_impl(PySetObject *so, PyObject * const *others,
PyObject *const *args); Py_ssize_t others_length);
static PyObject * static PyObject *
set_intersection_update_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) set_intersection_update_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
Py_ssize_t nvararg = nargs - 0; PyObject * const *others;
PyObject *const *__clinic_args = NULL; Py_ssize_t others_length;
if (!_PyArg_CheckPositional("intersection_update", nargs, 0, PY_SSIZE_T_MAX)) { others = args;
goto exit; others_length = nargs;
} return_value = set_intersection_update_multi_impl(so, others, others_length);
__clinic_args = args + 0;
return_value = set_intersection_update_multi_impl(so, nvararg, __clinic_args);
exit:
return return_value; return return_value;
} }
@ -255,23 +244,20 @@ PyDoc_STRVAR(set_difference_update__doc__,
{"difference_update", _PyCFunction_CAST(set_difference_update), METH_FASTCALL, set_difference_update__doc__}, {"difference_update", _PyCFunction_CAST(set_difference_update), METH_FASTCALL, set_difference_update__doc__},
static PyObject * static PyObject *
set_difference_update_impl(PySetObject *so, Py_ssize_t nargs, set_difference_update_impl(PySetObject *so, PyObject * const *others,
PyObject *const *args); Py_ssize_t others_length);
static PyObject * static PyObject *
set_difference_update(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) set_difference_update(PySetObject *so, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
Py_ssize_t nvararg = nargs - 0; PyObject * const *others;
PyObject *const *__clinic_args = NULL; Py_ssize_t others_length;
if (!_PyArg_CheckPositional("difference_update", nargs, 0, PY_SSIZE_T_MAX)) { others = args;
goto exit; others_length = nargs;
} return_value = set_difference_update_impl(so, others, others_length);
__clinic_args = args + 0;
return_value = set_difference_update_impl(so, nvararg, __clinic_args);
exit:
return return_value; return return_value;
} }
@ -285,23 +271,20 @@ PyDoc_STRVAR(set_difference_multi__doc__,
{"difference", _PyCFunction_CAST(set_difference_multi), METH_FASTCALL, set_difference_multi__doc__}, {"difference", _PyCFunction_CAST(set_difference_multi), METH_FASTCALL, set_difference_multi__doc__},
static PyObject * static PyObject *
set_difference_multi_impl(PySetObject *so, Py_ssize_t nargs, set_difference_multi_impl(PySetObject *so, PyObject * const *others,
PyObject *const *args); Py_ssize_t others_length);
static PyObject * static PyObject *
set_difference_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) set_difference_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
Py_ssize_t nvararg = nargs - 0; PyObject * const *others;
PyObject *const *__clinic_args = NULL; Py_ssize_t others_length;
if (!_PyArg_CheckPositional("difference", nargs, 0, PY_SSIZE_T_MAX)) { others = args;
goto exit; others_length = nargs;
} return_value = set_difference_multi_impl(so, others, others_length);
__clinic_args = args + 0;
return_value = set_difference_multi_impl(so, nvararg, __clinic_args);
exit:
return return_value; return return_value;
} }
@ -536,4 +519,4 @@ set___sizeof__(PySetObject *so, PyObject *Py_UNUSED(ignored))
return return_value; return return_value;
} }
/*[clinic end generated code: output=9d4b41191b2c602f input=a9049054013a1b77]*/ /*[clinic end generated code: output=4b65e7709927f31f input=a9049054013a1b77]*/

View File

@ -49,7 +49,7 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
.kwtuple = KWTUPLE, .kwtuple = KWTUPLE,
}; };
#undef KWTUPLE #undef KWTUPLE
PyObject *argsbuf[7]; PyObject *argsbuf[6];
PyObject * const *fastargs; PyObject * const *fastargs;
Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t nargs = PyTuple_GET_SIZE(args);
Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1;
@ -61,7 +61,7 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
int contravariant = 0; int contravariant = 0;
int infer_variance = 0; int infer_variance = 0;
fastargs = _PyArg_UnpackKeywordsWithVararg(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, 1, argsbuf); fastargs = _PyArg_UnpackKeywordsWithVararg(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf);
if (!fastargs) { if (!fastargs) {
goto exit; goto exit;
} }
@ -70,24 +70,23 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
goto exit; goto exit;
} }
name = fastargs[0]; name = fastargs[0];
constraints = fastargs[1];
if (!noptargs) { if (!noptargs) {
goto skip_optional_kwonly; goto skip_optional_kwonly;
} }
if (fastargs[1]) {
bound = fastargs[1];
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
if (fastargs[2]) { if (fastargs[2]) {
bound = fastargs[2]; default_value = fastargs[2];
if (!--noptargs) { if (!--noptargs) {
goto skip_optional_kwonly; goto skip_optional_kwonly;
} }
} }
if (fastargs[3]) { if (fastargs[3]) {
default_value = fastargs[3]; covariant = PyObject_IsTrue(fastargs[3]);
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
if (fastargs[4]) {
covariant = PyObject_IsTrue(fastargs[4]);
if (covariant < 0) { if (covariant < 0) {
goto exit; goto exit;
} }
@ -95,8 +94,8 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
goto skip_optional_kwonly; goto skip_optional_kwonly;
} }
} }
if (fastargs[5]) { if (fastargs[4]) {
contravariant = PyObject_IsTrue(fastargs[5]); contravariant = PyObject_IsTrue(fastargs[4]);
if (contravariant < 0) { if (contravariant < 0) {
goto exit; goto exit;
} }
@ -104,15 +103,21 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
goto skip_optional_kwonly; goto skip_optional_kwonly;
} }
} }
infer_variance = PyObject_IsTrue(fastargs[6]); infer_variance = PyObject_IsTrue(fastargs[5]);
if (infer_variance < 0) { if (infer_variance < 0) {
goto exit; goto exit;
} }
skip_optional_kwonly: skip_optional_kwonly:
constraints = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
if (!constraints) {
goto exit;
}
return_value = typevar_new_impl(type, name, constraints, bound, default_value, covariant, contravariant, infer_variance); return_value = typevar_new_impl(type, name, constraints, bound, default_value, covariant, contravariant, infer_variance);
exit: exit:
/* Cleanup for constraints */
Py_XDECREF(constraints); Py_XDECREF(constraints);
return return_value; return return_value;
} }
@ -695,4 +700,4 @@ skip_optional_kwonly:
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=73b39e550e4e336c input=a9049054013a1b77]*/ /*[clinic end generated code: output=32b9e6ced80d3fb0 input=a9049054013a1b77]*/

View File

@ -1054,19 +1054,20 @@ set_update_internal(PySetObject *so, PyObject *other)
/*[clinic input] /*[clinic input]
set.update set.update
so: setobject so: setobject
*others as args: object *others: array
Update the set, adding elements from all others. Update the set, adding elements from all others.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
set_update_impl(PySetObject *so, Py_ssize_t nargs, PyObject *const *args) set_update_impl(PySetObject *so, PyObject * const *others,
/*[clinic end generated code: output=050e2a21f8d7d16a input=df4fe486e38cd337]*/ Py_ssize_t others_length)
/*[clinic end generated code: output=017c781c992d5c23 input=ed5d78885b076636]*/
{ {
Py_ssize_t i; Py_ssize_t i;
for (i = 0; i < nargs; i++) { for (i = 0; i < others_length; i++) {
PyObject *other = args[i]; PyObject *other = others[i];
if (set_update_internal(so, other)) if (set_update_internal(so, other))
return NULL; return NULL;
} }
@ -1283,14 +1284,15 @@ set_clear_impl(PySetObject *so)
/*[clinic input] /*[clinic input]
set.union set.union
so: setobject so: setobject
*others as args: object *others: array
Return a new set with elements from the set and all others. Return a new set with elements from the set and all others.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
set_union_impl(PySetObject *so, Py_ssize_t nargs, PyObject *const *args) set_union_impl(PySetObject *so, PyObject * const *others,
/*[clinic end generated code: output=f68ec24d5c19d404 input=ddf088706e9577b2]*/ Py_ssize_t others_length)
/*[clinic end generated code: output=b1bfa3d74065f27e input=55a2e81db6347a4f]*/
{ {
PySetObject *result; PySetObject *result;
PyObject *other; PyObject *other;
@ -1300,8 +1302,8 @@ set_union_impl(PySetObject *so, Py_ssize_t nargs, PyObject *const *args)
if (result == NULL) if (result == NULL)
return NULL; return NULL;
for (i = 0; i < nargs; i++) { for (i = 0; i < others_length; i++) {
other = args[i]; other = others[i];
if ((PyObject *)so == other) if ((PyObject *)so == other)
continue; continue;
if (set_update_local(result, other)) { if (set_update_local(result, other)) {
@ -1434,25 +1436,25 @@ set_intersection(PySetObject *so, PyObject *other)
/*[clinic input] /*[clinic input]
set.intersection as set_intersection_multi set.intersection as set_intersection_multi
so: setobject so: setobject
*others as args: object *others: array
Return a new set with elements common to the set and all others. Return a new set with elements common to the set and all others.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
set_intersection_multi_impl(PySetObject *so, Py_ssize_t nargs, set_intersection_multi_impl(PySetObject *so, PyObject * const *others,
PyObject *const *args) Py_ssize_t others_length)
/*[clinic end generated code: output=ef0756ddb5f2dee9 input=0d9f3805ccbba6a4]*/ /*[clinic end generated code: output=db9ff9f875132b6b input=36c7b615694cadae]*/
{ {
Py_ssize_t i; Py_ssize_t i;
if (nargs == 0) { if (others_length == 0) {
return set_copy(so, NULL); return set_copy(so, NULL);
} }
PyObject *result = Py_NewRef(so); PyObject *result = Py_NewRef(so);
for (i = 0; i < nargs; i++) { for (i = 0; i < others_length; i++) {
PyObject *other = args[i]; PyObject *other = others[i];
PyObject *newresult; PyObject *newresult;
Py_BEGIN_CRITICAL_SECTION2(result, other); Py_BEGIN_CRITICAL_SECTION2(result, other);
newresult = set_intersection((PySetObject *)result, other); newresult = set_intersection((PySetObject *)result, other);
@ -1482,19 +1484,19 @@ set_intersection_update(PySetObject *so, PyObject *other)
/*[clinic input] /*[clinic input]
set.intersection_update as set_intersection_update_multi set.intersection_update as set_intersection_update_multi
so: setobject so: setobject
*others as args: object *others: array
Update the set, keeping only elements found in it and all others. Update the set, keeping only elements found in it and all others.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
set_intersection_update_multi_impl(PySetObject *so, Py_ssize_t nargs, set_intersection_update_multi_impl(PySetObject *so, PyObject * const *others,
PyObject *const *args) Py_ssize_t others_length)
/*[clinic end generated code: output=808d7ad1935b1dfe input=223c1e086aa669a9]*/ /*[clinic end generated code: output=d768b5584675b48d input=782e422fc370e4fc]*/
{ {
PyObject *tmp; PyObject *tmp;
tmp = set_intersection_multi_impl(so, nargs, args); tmp = set_intersection_multi_impl(so, others, others_length);
if (tmp == NULL) if (tmp == NULL)
return NULL; return NULL;
Py_BEGIN_CRITICAL_SECTION(so); Py_BEGIN_CRITICAL_SECTION(so);
@ -1672,20 +1674,20 @@ set_difference_update_internal(PySetObject *so, PyObject *other)
/*[clinic input] /*[clinic input]
set.difference_update set.difference_update
so: setobject so: setobject
*others as args: object *others: array
Update the set, removing elements found in others. Update the set, removing elements found in others.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
set_difference_update_impl(PySetObject *so, Py_ssize_t nargs, set_difference_update_impl(PySetObject *so, PyObject * const *others,
PyObject *const *args) Py_ssize_t others_length)
/*[clinic end generated code: output=55f850c27748d312 input=024e6baa6fbcbb3d]*/ /*[clinic end generated code: output=04a22179b322cfe6 input=93ac28ba5b233696]*/
{ {
Py_ssize_t i; Py_ssize_t i;
for (i = 0; i < nargs; i++) { for (i = 0; i < others_length; i++) {
PyObject *other = args[i]; PyObject *other = others[i];
int rv; int rv;
Py_BEGIN_CRITICAL_SECTION2(so, other); Py_BEGIN_CRITICAL_SECTION2(so, other);
rv = set_difference_update_internal(so, other); rv = set_difference_update_internal(so, other);
@ -1790,32 +1792,32 @@ set_difference(PySetObject *so, PyObject *other)
/*[clinic input] /*[clinic input]
set.difference as set_difference_multi set.difference as set_difference_multi
so: setobject so: setobject
*others as args: object *others: array
Return a new set with elements in the set that are not in the others. Return a new set with elements in the set that are not in the others.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
set_difference_multi_impl(PySetObject *so, Py_ssize_t nargs, set_difference_multi_impl(PySetObject *so, PyObject * const *others,
PyObject *const *args) Py_ssize_t others_length)
/*[clinic end generated code: output=8150d008c00523f3 input=ba78ea5f099e58df]*/ /*[clinic end generated code: output=b0d33fb05d5477a7 input=c1eb448d483416ad]*/
{ {
Py_ssize_t i; Py_ssize_t i;
PyObject *result, *other; PyObject *result, *other;
if (nargs == 0) { if (others_length == 0) {
return set_copy(so, NULL); return set_copy(so, NULL);
} }
other = args[0]; other = others[0];
Py_BEGIN_CRITICAL_SECTION2(so, other); Py_BEGIN_CRITICAL_SECTION2(so, other);
result = set_difference(so, other); result = set_difference(so, other);
Py_END_CRITICAL_SECTION2(); Py_END_CRITICAL_SECTION2();
if (result == NULL) if (result == NULL)
return NULL; return NULL;
for (i = 1; i < nargs; i++) { for (i = 1; i < others_length; i++) {
other = args[i]; other = others[i];
int rv; int rv;
Py_BEGIN_CRITICAL_SECTION(other); Py_BEGIN_CRITICAL_SECTION(other);
rv = set_difference_update_internal((PySetObject *)result, other); rv = set_difference_update_internal((PySetObject *)result, other);

View File

@ -7,6 +7,7 @@ preserve
# include "pycore_runtime.h" // _Py_ID() # include "pycore_runtime.h" // _Py_ID()
#endif #endif
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
#include "pycore_tuple.h" // _PyTuple_FromArray()
PyDoc_STRVAR(builtin___import____doc__, PyDoc_STRVAR(builtin___import____doc__,
"__import__($module, /, name, globals=None, locals=None, fromlist=(),\n" "__import__($module, /, name, globals=None, locals=None, fromlist=(),\n"
@ -933,7 +934,8 @@ builtin_print(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec
.kwtuple = KWTUPLE, .kwtuple = KWTUPLE,
}; };
#undef KWTUPLE #undef KWTUPLE
PyObject *argsbuf[5]; PyObject *argsbuf[4];
PyObject * const *fastargs;
Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
PyObject *__clinic_args = NULL; PyObject *__clinic_args = NULL;
PyObject *sep = Py_None; PyObject *sep = Py_None;
@ -941,41 +943,46 @@ builtin_print(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec
PyObject *file = Py_None; PyObject *file = Py_None;
int flush = 0; int flush = 0;
args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf);
if (!args) { if (!fastargs) {
goto exit; goto exit;
} }
__clinic_args = args[0];
if (!noptargs) { if (!noptargs) {
goto skip_optional_kwonly; goto skip_optional_kwonly;
} }
if (args[1]) { if (fastargs[0]) {
sep = args[1]; sep = fastargs[0];
if (!--noptargs) { if (!--noptargs) {
goto skip_optional_kwonly; goto skip_optional_kwonly;
} }
} }
if (args[2]) { if (fastargs[1]) {
end = args[2]; end = fastargs[1];
if (!--noptargs) { if (!--noptargs) {
goto skip_optional_kwonly; goto skip_optional_kwonly;
} }
} }
if (args[3]) { if (fastargs[2]) {
file = args[3]; file = fastargs[2];
if (!--noptargs) { if (!--noptargs) {
goto skip_optional_kwonly; goto skip_optional_kwonly;
} }
} }
flush = PyObject_IsTrue(args[4]); flush = PyObject_IsTrue(fastargs[3]);
if (flush < 0) { if (flush < 0) {
goto exit; goto exit;
} }
skip_optional_kwonly: skip_optional_kwonly:
__clinic_args = _PyTuple_FromArray(args, nargs);
if (__clinic_args == NULL) {
goto exit;
}
return_value = builtin_print_impl(module, __clinic_args, sep, end, file, flush); return_value = builtin_print_impl(module, __clinic_args, sep, end, file, flush);
exit: exit:
/* Cleanup for args */
Py_XDECREF(__clinic_args); Py_XDECREF(__clinic_args);
return return_value; return return_value;
} }
@ -1228,4 +1235,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=435d3f286a863c49 input=a9049054013a1b77]*/ /*[clinic end generated code: output=76b27cf4164f257e input=a9049054013a1b77]*/

View File

@ -2308,13 +2308,11 @@ vgetargskeywordsfast(PyObject *args, PyObject *keywords,
} }
#undef _PyArg_UnpackKeywords
PyObject * const * PyObject * const *
_PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, _PyArg_UnpackKeywordsEx(PyObject *const *args, Py_ssize_t nargs,
PyObject *kwargs, PyObject *kwnames, PyObject *kwargs, PyObject *kwnames,
struct _PyArg_Parser *parser, struct _PyArg_Parser *parser,
int minpos, int maxpos, int minkw, int minpos, int maxpos, int minkw, int varpos,
PyObject **buf) PyObject **buf)
{ {
PyObject *kwtuple; PyObject *kwtuple;
@ -2360,11 +2358,11 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs,
else { else {
nkwargs = 0; nkwargs = 0;
} }
if (nkwargs == 0 && minkw == 0 && minpos <= nargs && nargs <= maxpos) { if (nkwargs == 0 && minkw == 0 && minpos <= nargs && (varpos || nargs <= maxpos)) {
/* Fast path. */ /* Fast path. */
return args; return args;
} }
if (nargs + nkwargs > maxargs) { if (!varpos && nargs + nkwargs > maxargs) {
/* Adding "keyword" (when nargs == 0) prevents producing wrong error /* Adding "keyword" (when nargs == 0) prevents producing wrong error
messages in some special cases (see bpo-31229). */ messages in some special cases (see bpo-31229). */
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
@ -2377,7 +2375,7 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs,
nargs + nkwargs); nargs + nkwargs);
return NULL; return NULL;
} }
if (nargs > maxpos) { if (!varpos && nargs > maxpos) {
if (maxpos == 0) { if (maxpos == 0) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%.200s%s takes no positional arguments", "%.200s%s takes no positional arguments",
@ -2402,13 +2400,16 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs,
" (%zd given)", " (%zd given)",
(parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "function" : parser->fname,
(parser->fname == NULL) ? "" : "()", (parser->fname == NULL) ? "" : "()",
minposonly < maxpos ? "at least" : "exactly", (varpos || minposonly < maxpos) ? "at least" : "exactly",
minposonly, minposonly,
minposonly == 1 ? "" : "s", minposonly == 1 ? "" : "s",
nargs); nargs);
return NULL; return NULL;
} }
if (varpos) {
nargs = Py_MIN(maxpos, nargs);
}
/* copy tuple args */ /* copy tuple args */
for (i = 0; i < nargs; i++) { for (i = 0; i < nargs; i++) {
buf[i] = args[i]; buf[i] = args[i];
@ -2486,157 +2487,6 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs,
return buf; return buf;
} }
PyObject * const *
_PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs,
PyObject *kwargs, PyObject *kwnames,
struct _PyArg_Parser *parser,
int minpos, int maxpos, int minkw,
int vararg, PyObject **buf)
{
PyObject *kwtuple;
PyObject *keyword;
Py_ssize_t varargssize = 0;
int i, posonly, minposonly, maxargs;
int reqlimit = minkw ? maxpos + minkw : minpos;
Py_ssize_t nkwargs;
PyObject * const *kwstack = NULL;
assert(kwargs == NULL || PyDict_Check(kwargs));
assert(kwargs == NULL || kwnames == NULL);
if (parser == NULL) {
PyErr_BadInternalCall();
return NULL;
}
if (kwnames != NULL && !PyTuple_Check(kwnames)) {
PyErr_BadInternalCall();
return NULL;
}
if (args == NULL && nargs == 0) {
args = buf;
}
if (parser_init(parser) < 0) {
return NULL;
}
kwtuple = parser->kwtuple;
posonly = parser->pos;
minposonly = Py_MIN(posonly, minpos);
maxargs = posonly + (int)PyTuple_GET_SIZE(kwtuple);
if (kwargs != NULL) {
nkwargs = PyDict_GET_SIZE(kwargs);
}
else if (kwnames != NULL) {
nkwargs = PyTuple_GET_SIZE(kwnames);
kwstack = args + nargs;
}
else {
nkwargs = 0;
}
if (nargs < minposonly) {
PyErr_Format(PyExc_TypeError,
"%.200s%s takes %s %d positional argument%s"
" (%zd given)",
(parser->fname == NULL) ? "function" : parser->fname,
(parser->fname == NULL) ? "" : "()",
minposonly < maxpos ? "at least" : "exactly",
minposonly,
minposonly == 1 ? "" : "s",
nargs);
return NULL;
}
/* create varargs tuple */
varargssize = nargs - maxpos;
if (varargssize < 0) {
varargssize = 0;
}
buf[vararg] = PyTuple_New(varargssize);
if (!buf[vararg]) {
return NULL;
}
/* copy tuple args */
for (i = 0; i < nargs; i++) {
if (i >= vararg) {
PyTuple_SET_ITEM(buf[vararg], i - vararg, Py_NewRef(args[i]));
continue;
}
else {
buf[i] = args[i];
}
}
/* copy keyword args using kwtuple to drive process */
for (i = Py_MAX((int)nargs, posonly) - Py_SAFE_DOWNCAST(varargssize, Py_ssize_t, int); i < maxargs; i++) {
PyObject *current_arg;
if (nkwargs) {
keyword = PyTuple_GET_ITEM(kwtuple, i - posonly);
if (kwargs != NULL) {
if (PyDict_GetItemRef(kwargs, keyword, &current_arg) < 0) {
goto exit;
}
}
else {
current_arg = find_keyword(kwnames, kwstack, keyword);
}
}
else {
current_arg = NULL;
}
/* If an arguments is passed in as a keyword argument,
* it should be placed before `buf[vararg]`.
*
* For example:
* def f(a, /, b, *args):
* pass
* f(1, b=2)
*
* This `buf` array should be: [1, 2, NULL].
* In this case, nargs < vararg.
*
* Otherwise, we leave a place at `buf[vararg]` for vararg tuple
* so the index is `i + 1`. */
if (i < vararg) {
buf[i] = current_arg;
}
else {
buf[i + 1] = current_arg;
}
if (current_arg) {
Py_DECREF(current_arg);
--nkwargs;
}
else if (i < minpos || (maxpos <= i && i < reqlimit)) {
/* Less arguments than required */
keyword = PyTuple_GET_ITEM(kwtuple, i - posonly);
PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
"argument '%U' (pos %d)",
(parser->fname == NULL) ? "function" : parser->fname,
(parser->fname == NULL) ? "" : "()",
keyword, i+1);
goto exit;
}
}
if (nkwargs > 0) {
error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname);
goto exit;
}
return buf;
exit:
Py_XDECREF(buf[vararg]);
return NULL;
}
static const char * static const char *
skipitem(const char **p_format, va_list *p_va, int flags) skipitem(const char **p_format, va_list *p_va, int flags)
{ {

View File

@ -164,7 +164,7 @@ def _parse(srclines, anon_name, **srckwargs):
# We use defaults that cover most files. Files with bigger declarations # We use defaults that cover most files. Files with bigger declarations
# are covered elsewhere (MAX_SIZES in cpython/_parser.py). # are covered elsewhere (MAX_SIZES in cpython/_parser.py).
def _iter_source(lines, *, maxtext=10_000, maxlines=200, showtext=False): def _iter_source(lines, *, maxtext=11_000, maxlines=200, showtext=False):
maxtext = maxtext if maxtext and maxtext > 0 else None maxtext = maxtext if maxtext and maxtext > 0 else None
maxlines = maxlines if maxlines and maxlines > 0 else None maxlines = maxlines if maxlines and maxlines > 0 else None
filestack = [] filestack = []

View File

@ -15,7 +15,7 @@ from libclinic.function import (
Module, Class, Function, Parameter, Module, Class, Function, Parameter,
permute_optional_groups, permute_optional_groups,
GETTER, SETTER, METHOD_INIT) GETTER, SETTER, METHOD_INIT)
from libclinic.converters import defining_class_converter, self_converter from libclinic.converters import self_converter
from libclinic.parse_args import ParseArgsCodeGen from libclinic.parse_args import ParseArgsCodeGen
if TYPE_CHECKING: if TYPE_CHECKING:
from libclinic.app import Clinic from libclinic.app import Clinic
@ -396,12 +396,6 @@ class CLanguage(Language):
first_optional = len(selfless) first_optional = len(selfless)
positional = selfless and selfless[-1].is_positional_only() positional = selfless and selfless[-1].is_positional_only()
has_option_groups = False has_option_groups = False
requires_defining_class = (len(selfless)
and isinstance(selfless[0].converter,
defining_class_converter))
pass_vararg_directly = (all(p.is_positional_only() or p.is_vararg()
for p in selfless)
and not requires_defining_class)
# offset i by -1 because first_optional needs to ignore self # offset i by -1 because first_optional needs to ignore self
for i, p in enumerate(parameters, -1): for i, p in enumerate(parameters, -1):
@ -410,9 +404,6 @@ class CLanguage(Language):
if (i != -1) and (p.default is not unspecified): if (i != -1) and (p.default is not unspecified):
first_optional = min(first_optional, i) first_optional = min(first_optional, i)
if p.is_vararg() and not pass_vararg_directly:
data.cleanup.append(f"Py_XDECREF({c.parser_name});")
# insert group variable # insert group variable
group = p.group group = p.group
if last_group != group: if last_group != group:
@ -424,11 +415,6 @@ class CLanguage(Language):
data.impl_parameters.append("int " + group_name) data.impl_parameters.append("int " + group_name)
has_option_groups = True has_option_groups = True
if p.is_vararg() and pass_vararg_directly:
data.impl_arguments.append('nvararg')
data.impl_parameters.append('Py_ssize_t nargs')
p.converter.type = 'PyObject *const *'
c.render(p, data) c.render(p, data)
if has_option_groups and (not positional): if has_option_groups and (not positional):

View File

@ -312,7 +312,7 @@ class CConverter(metaclass=CConverterAutoRegister):
def length_name(self) -> str: def length_name(self) -> str:
"""Computes the name of the associated "length" variable.""" """Computes the name of the associated "length" variable."""
assert self.length is not None assert self.length is not None
return self.parser_name + "_length" return self.name + "_length"
# Why is this one broken out separately? # Why is this one broken out separately?
# For "positional-only" function parsing, # For "positional-only" function parsing,

View File

@ -1228,3 +1228,30 @@ class self_converter(CConverter):
type_object = cls.type_object type_object = cls.type_object
type_ptr = f'PyTypeObject *base_tp = {type_object};' type_ptr = f'PyTypeObject *base_tp = {type_object};'
template_dict['base_type_ptr'] = type_ptr template_dict['base_type_ptr'] = type_ptr
# Converters for var-positional parameter.
class varpos_tuple_converter(CConverter):
type = 'PyObject *'
format_unit = ''
c_default = 'NULL'
def cleanup(self) -> str:
return f"""Py_XDECREF({self.parser_name});\n"""
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
raise AssertionError('should never be called')
class varpos_array_converter(CConverter):
type = 'PyObject * const *'
format_unit = ''
length = True
c_ignored_default = ''
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
raise AssertionError('should never be called')
# XXX: temporary
class varpos_object_converter(varpos_tuple_converter):
pass

View File

@ -925,16 +925,17 @@ class DSLParser:
parameter_name = parameter.arg parameter_name = parameter.arg
name, legacy, kwargs = self.parse_converter(parameter.annotation) name, legacy, kwargs = self.parse_converter(parameter.annotation)
if is_vararg:
name = 'varpos_' + name
value: object value: object
if not default: if not default:
if is_vararg:
value = NULL
else:
if self.parameter_state is ParamState.OPTIONAL: if self.parameter_state is ParamState.OPTIONAL:
fail(f"Can't have a parameter without a default ({parameter_name!r}) " fail(f"Can't have a parameter without a default ({parameter_name!r}) "
"after a parameter with a default!") "after a parameter with a default!")
if is_vararg:
value = NULL
kwargs.setdefault('c_default', "NULL")
else:
value = unspecified value = unspecified
if 'py_default' in kwargs: if 'py_default' in kwargs:
fail("You can't specify py_default without specifying a default value!") fail("You can't specify py_default without specifying a default value!")

View File

@ -217,8 +217,7 @@ class ParseArgsCodeGen:
min_pos: int = 0 min_pos: int = 0
max_pos: int = 0 max_pos: int = 0
min_kw_only: int = 0 min_kw_only: int = 0
pseudo_args: int = 0 varpos: Parameter | None = None
vararg: int | str = NO_VARARG
docstring_prototype: str docstring_prototype: str
docstring_definition: str docstring_definition: str
@ -246,6 +245,13 @@ class ParseArgsCodeGen:
if self.parameters and isinstance(self.parameters[0].converter, defining_class_converter): if self.parameters and isinstance(self.parameters[0].converter, defining_class_converter):
self.requires_defining_class = True self.requires_defining_class = True
del self.parameters[0] del self.parameters[0]
for i, p in enumerate(self.parameters):
if p.is_vararg():
self.varpos = p
del self.parameters[i]
break
self.converters = [p.converter for p in self.parameters] self.converters = [p.converter for p in self.parameters]
if self.func.critical_section: if self.func.critical_section:
@ -257,17 +263,12 @@ class ParseArgsCodeGen:
self.min_pos = 0 self.min_pos = 0
self.max_pos = 0 self.max_pos = 0
self.min_kw_only = 0 self.min_kw_only = 0
self.pseudo_args = 0
for i, p in enumerate(self.parameters, 1): for i, p in enumerate(self.parameters, 1):
if p.is_keyword_only(): if p.is_keyword_only():
assert not p.is_positional_only() assert not p.is_positional_only()
if not p.is_optional(): if not p.is_optional():
self.min_kw_only = i - self.max_pos - int(self.vararg != NO_VARARG) self.min_kw_only = i - self.max_pos
elif p.is_vararg():
self.pseudo_args += 1
self.vararg = i - 1
else: else:
if self.vararg == NO_VARARG:
self.max_pos = i self.max_pos = i
if p.is_positional_only(): if p.is_positional_only():
self.pos_only = i self.pos_only = i
@ -285,6 +286,7 @@ class ParseArgsCodeGen:
return (len(self.parameters) == 1 return (len(self.parameters) == 1
and self.parameters[0].is_positional_only() and self.parameters[0].is_positional_only()
and not self.converters[0].is_optional() and not self.converters[0].is_optional()
and not self.varpos
and not self.requires_defining_class and not self.requires_defining_class
and not self.is_new_or_init()) and not self.is_new_or_init())
@ -315,7 +317,8 @@ class ParseArgsCodeGen:
def init_limited_capi(self) -> None: def init_limited_capi(self) -> None:
self.limited_capi = self.codegen.limited_capi self.limited_capi = self.codegen.limited_capi
if self.limited_capi and (self.pseudo_args or if self.limited_capi and (
(self.varpos and self.pos_only < len(self.parameters)) or
(any(p.is_optional() for p in self.parameters) and (any(p.is_optional() for p in self.parameters) and
any(p.is_keyword_only() and not p.is_optional() for p in self.parameters)) or any(p.is_keyword_only() and not p.is_optional() for p in self.parameters)) or
any(c.broken_limited_capi for c in self.converters)): any(c.broken_limited_capi for c in self.converters)):
@ -447,6 +450,74 @@ class ParseArgsCodeGen:
parser_code = ' {option_group_parsing}' parser_code = ' {option_group_parsing}'
self.parser_body(parser_code) self.parser_body(parser_code)
def _parse_vararg(self) -> str:
assert self.varpos is not None
paramname = self.varpos.converter.parser_name
if self.varpos.converter.length:
if not self.fastcall:
self.codegen.add_include('pycore_tuple.h',
'_PyTuple_ITEMS()')
start = 'args' if self.fastcall else '_PyTuple_ITEMS(args)'
size = 'nargs' if self.fastcall else 'PyTuple_GET_SIZE(args)'
if self.max_pos:
if min(self.pos_only, self.min_pos) < self.max_pos:
start = f'{size} > {self.max_pos} ? {start} + {self.max_pos} : {start}'
size = f'Py_MAX(0, {size} - {self.max_pos})'
else:
start = f'{start} + {self.max_pos}'
size = f'{size} - {self.max_pos}'
return f"""
{paramname} = {start};
{self.varpos.converter.length_name} = {size};
"""
if self.fastcall:
if self.limited_capi:
if min(self.pos_only, self.min_pos) < self.max_pos:
size = f'Py_MAX(nargs - {self.max_pos}, 0)'
else:
size = f'nargs - {self.max_pos}' if self.max_pos else 'nargs'
return f"""
{paramname} = PyTuple_New({size});
if (!{paramname}) {{{{
goto exit;
}}}}
for (Py_ssize_t i = {self.max_pos}; i < nargs; ++i) {{{{
PyTuple_SET_ITEM({paramname}, i - {self.max_pos}, Py_NewRef(args[i]));
}}}}
"""
else:
self.codegen.add_include('pycore_tuple.h',
'_PyTuple_FromArray()')
if min(self.pos_only, self.min_pos) < self.max_pos:
return f"""
{paramname} = nargs > {self.max_pos}
? _PyTuple_FromArray(args + {self.max_pos}, nargs - {self.max_pos})
: PyTuple_New(0);
if ({paramname} == NULL) {{{{
goto exit;
}}}}
"""
else:
start = f'args + {self.max_pos}' if self.max_pos else 'args'
size = f'nargs - {self.max_pos}' if self.max_pos else 'nargs'
return f"""
{paramname} = _PyTuple_FromArray({start}, {size});
if ({paramname} == NULL) {{{{
goto exit;
}}}}
"""
else:
if self.max_pos:
return f"""
{paramname} = PyTuple_GetSlice(args, {self.max_pos}, PY_SSIZE_T_MAX);
if (!{paramname}) {{{{
goto exit;
}}}}
"""
else:
return f"{paramname} = Py_NewRef(args);\n"
def parse_pos_only(self) -> None: def parse_pos_only(self) -> None:
if self.fastcall: if self.fastcall:
# positional-only, but no option groups # positional-only, but no option groups
@ -469,14 +540,9 @@ class ParseArgsCodeGen:
nargs = 'PyTuple_GET_SIZE(args)' nargs = 'PyTuple_GET_SIZE(args)'
argname_fmt = 'PyTuple_GET_ITEM(args, %d)' argname_fmt = 'PyTuple_GET_ITEM(args, %d)'
if self.vararg != NO_VARARG:
self.declarations = f"Py_ssize_t nvararg = {nargs} - {self.max_pos};"
else:
self.declarations = ""
max_args = NO_VARARG if (self.vararg != NO_VARARG) else self.max_pos
if self.limited_capi:
parser_code = [] parser_code = []
max_args = NO_VARARG if self.varpos else self.max_pos
if self.limited_capi:
if nargs != 'nargs': if nargs != 'nargs':
nargs_def = f'Py_ssize_t nargs = {nargs};' nargs_def = f'Py_ssize_t nargs = {nargs};'
parser_code.append(libclinic.normalize_snippet(nargs_def, indent=4)) parser_code.append(libclinic.normalize_snippet(nargs_def, indent=4))
@ -509,33 +575,27 @@ class ParseArgsCodeGen:
}}}} }}}}
""", """,
indent=4)) indent=4))
else: elif self.min_pos or max_args != NO_VARARG:
self.codegen.add_include('pycore_modsupport.h', self.codegen.add_include('pycore_modsupport.h',
'_PyArg_CheckPositional()') '_PyArg_CheckPositional()')
parser_code = [libclinic.normalize_snippet(f""" parser_code.append(libclinic.normalize_snippet(f"""
if (!_PyArg_CheckPositional("{{name}}", {nargs}, {self.min_pos}, {max_args})) {{{{ if (!_PyArg_CheckPositional("{{name}}", {nargs}, {self.min_pos}, {max_args})) {{{{
goto exit; goto exit;
}}}} }}}}
""", indent=4)] """, indent=4))
has_optional = False has_optional = False
use_parser_code = True use_parser_code = True
for i, p in enumerate(self.parameters): for i, p in enumerate(self.parameters):
if p.is_vararg():
var = p.converter.parser_name
if self.fastcall:
code = f"{var} = args + {self.vararg};"
else:
code = f"{var} = _PyTuple_CAST(args)->ob_item;"
formatted_code = libclinic.normalize_snippet(code, indent=4)
parser_code.append(formatted_code)
continue
displayname = p.get_displayname(i+1) displayname = p.get_displayname(i+1)
argname = argname_fmt % i argname = argname_fmt % i
parsearg: str | None parsearg: str | None
parsearg = p.converter.parse_arg(argname, displayname, limited_capi=self.limited_capi) parsearg = p.converter.parse_arg(argname, displayname, limited_capi=self.limited_capi)
if parsearg is None: if parsearg is None:
if self.varpos:
raise ValueError(
f"Using converter {p.converter} is not supported "
f"in function with var-positional parameter")
use_parser_code = False use_parser_code = False
parser_code = [] parser_code = []
break break
@ -551,6 +611,8 @@ class ParseArgsCodeGen:
if use_parser_code: if use_parser_code:
if has_optional: if has_optional:
parser_code.append("skip_optional:") parser_code.append("skip_optional:")
if self.varpos:
parser_code.append(libclinic.normalize_snippet(self._parse_vararg(), indent=4))
else: else:
for parameter in self.parameters: for parameter in self.parameters:
parameter.converter.use_converter() parameter.converter.use_converter()
@ -575,7 +637,7 @@ class ParseArgsCodeGen:
goto exit; goto exit;
}} }}
""", indent=4)] """, indent=4)]
self.parser_body(*parser_code, declarations=self.declarations) self.parser_body(*parser_code)
def parse_general(self, clang: CLanguage) -> None: def parse_general(self, clang: CLanguage) -> None:
parsearg: str | None parsearg: str | None
@ -589,7 +651,7 @@ class ParseArgsCodeGen:
has_optional_kw = ( has_optional_kw = (
max(self.pos_only, self.min_pos) + self.min_kw_only max(self.pos_only, self.min_pos) + self.min_kw_only
< len(self.converters) - int(self.vararg != NO_VARARG) < len(self.converters)
) )
use_parser_code = True use_parser_code = True
@ -598,57 +660,53 @@ class ParseArgsCodeGen:
use_parser_code = False use_parser_code = False
self.fastcall = False self.fastcall = False
else: else:
if self.vararg == NO_VARARG: if not self.varpos:
self.codegen.add_include('pycore_modsupport.h', self.codegen.add_include('pycore_modsupport.h',
'_PyArg_UnpackKeywords()') '_PyArg_UnpackKeywords()')
args_declaration = "_PyArg_UnpackKeywords", "%s, %s, %s" % ( unpack_func = '_PyArg_UnpackKeywords'
self.min_pos,
self.max_pos,
self.min_kw_only
)
nargs = "nargs" nargs = "nargs"
else: else:
self.codegen.add_include('pycore_modsupport.h', self.codegen.add_include('pycore_modsupport.h',
'_PyArg_UnpackKeywordsWithVararg()') '_PyArg_UnpackKeywordsWithVararg()')
args_declaration = "_PyArg_UnpackKeywordsWithVararg", "%s, %s, %s, %s" % ( unpack_func = '_PyArg_UnpackKeywordsWithVararg'
self.min_pos,
self.max_pos,
self.min_kw_only,
self.vararg
)
nargs = f"Py_MIN(nargs, {self.max_pos})" if self.max_pos else "0" nargs = f"Py_MIN(nargs, {self.max_pos})" if self.max_pos else "0"
if self.fastcall: if self.fastcall:
self.flags = "METH_FASTCALL|METH_KEYWORDS" self.flags = "METH_FASTCALL|METH_KEYWORDS"
self.parser_prototype = PARSER_PROTOTYPE_FASTCALL_KEYWORDS self.parser_prototype = PARSER_PROTOTYPE_FASTCALL_KEYWORDS
argname_fmt = 'args[%d]'
self.declarations = declare_parser(self.func, codegen=self.codegen) self.declarations = declare_parser(self.func, codegen=self.codegen)
self.declarations += "\nPyObject *argsbuf[%s];" % len(self.converters) self.declarations += "\nPyObject *argsbuf[%s];" % (len(self.converters) or 1)
if self.varpos:
self.declarations += "\nPyObject * const *fastargs;"
argsname = 'fastargs'
argname_fmt = 'fastargs[%d]'
else:
argsname = 'args'
argname_fmt = 'args[%d]'
if has_optional_kw: if has_optional_kw:
self.declarations += "\nPy_ssize_t noptargs = %s + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - %d;" % (nargs, self.min_pos + self.min_kw_only) self.declarations += "\nPy_ssize_t noptargs = %s + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - %d;" % (nargs, self.min_pos + self.min_kw_only)
parser_code = [libclinic.normalize_snippet(""" unpack_args = 'args, nargs, NULL, kwnames'
args = %s(args, nargs, NULL, kwnames, &_parser, %s, argsbuf);
if (!args) {{
goto exit;
}}
""" % args_declaration, indent=4)]
else: else:
# positional-or-keyword arguments # positional-or-keyword arguments
self.flags = "METH_VARARGS|METH_KEYWORDS" self.flags = "METH_VARARGS|METH_KEYWORDS"
self.parser_prototype = PARSER_PROTOTYPE_KEYWORD self.parser_prototype = PARSER_PROTOTYPE_KEYWORD
argsname = 'fastargs'
argname_fmt = 'fastargs[%d]' argname_fmt = 'fastargs[%d]'
self.declarations = declare_parser(self.func, codegen=self.codegen) self.declarations = declare_parser(self.func, codegen=self.codegen)
self.declarations += "\nPyObject *argsbuf[%s];" % len(self.converters) self.declarations += "\nPyObject *argsbuf[%s];" % (len(self.converters) or 1)
self.declarations += "\nPyObject * const *fastargs;" self.declarations += "\nPyObject * const *fastargs;"
self.declarations += "\nPy_ssize_t nargs = PyTuple_GET_SIZE(args);" self.declarations += "\nPy_ssize_t nargs = PyTuple_GET_SIZE(args);"
if has_optional_kw: if has_optional_kw:
self.declarations += "\nPy_ssize_t noptargs = %s + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - %d;" % (nargs, self.min_pos + self.min_kw_only) self.declarations += "\nPy_ssize_t noptargs = %s + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - %d;" % (nargs, self.min_pos + self.min_kw_only)
parser_code = [libclinic.normalize_snippet(""" unpack_args = '_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL'
fastargs = %s(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, %s, argsbuf); unpack_args += (f', &_parser, {self.min_pos}, {self.max_pos}, '
if (!fastargs) {{ f'{self.min_kw_only}, argsbuf')
parser_code = [libclinic.normalize_snippet(f"""
{argsname} = {unpack_func}({unpack_args});
if (!{argsname}) {{{{
goto exit; goto exit;
}} }}}}
""" % args_declaration, indent=4)] """, indent=4)]
if self.requires_defining_class: if self.requires_defining_class:
self.flags = 'METH_METHOD|' + self.flags self.flags = 'METH_METHOD|' + self.flags
@ -697,8 +755,6 @@ class ParseArgsCodeGen:
else: else:
label = 'skip_optional_kwonly' label = 'skip_optional_kwonly'
first_opt = self.max_pos + self.min_kw_only first_opt = self.max_pos + self.min_kw_only
if self.vararg != NO_VARARG:
first_opt += 1
if i == first_opt: if i == first_opt:
add_label = label add_label = label
parser_code.append(libclinic.normalize_snippet(""" parser_code.append(libclinic.normalize_snippet("""
@ -724,6 +780,8 @@ class ParseArgsCodeGen:
if use_parser_code: if use_parser_code:
if add_label: if add_label:
parser_code.append("%s:" % add_label) parser_code.append("%s:" % add_label)
if self.varpos:
parser_code.append(libclinic.normalize_snippet(self._parse_vararg(), indent=4))
else: else:
for parameter in self.parameters: for parameter in self.parameters:
parameter.converter.use_converter() parameter.converter.use_converter()
@ -914,14 +972,14 @@ class ParseArgsCodeGen:
# previous call to parser_body. this is used for an awful hack. # previous call to parser_body. this is used for an awful hack.
self.parser_body_fields: tuple[str, ...] = () self.parser_body_fields: tuple[str, ...] = ()
if not self.parameters: if not self.parameters and not self.varpos:
self.parse_no_args() self.parse_no_args()
elif self.use_meth_o(): elif self.use_meth_o():
self.parse_one_arg() self.parse_one_arg()
elif self.has_option_groups(): elif self.has_option_groups():
self.parse_option_groups() self.parse_option_groups()
elif (not self.requires_defining_class elif (not self.requires_defining_class
and self.pos_only == len(self.parameters) - self.pseudo_args): and self.pos_only == len(self.parameters)):
self.parse_pos_only() self.parse_pos_only()
else: else:
self.parse_general(clang) self.parse_general(clang)