@@ -187,6 +187,14 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
187187 if (state == NULL ) {
188188 return NULL ;
189189 }
190+ phold = state -> placeholder ;
191+
192+ /* Placeholder restrictions */
193+ if (new_nargs && PyTuple_GET_ITEM (args , new_nargs ) == phold ) {
194+ PyErr_SetString (PyExc_TypeError ,
195+ "trailing Placeholders are not allowed" );
196+ return NULL ;
197+ }
190198
191199 /* check wrapped function / object */
192200 pto_args = pto_kw = NULL ;
@@ -212,86 +220,66 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
212220 if (pto == NULL )
213221 return NULL ;
214222
215- phold = state -> placeholder ;
216223 pto -> fn = Py_NewRef (func );
217224 pto -> placeholder = phold ;
218225
219- /* process args */
220- if (new_nargs == 0 ) {
221- if (pto_args == NULL ) {
222- pto -> args = PyTuple_New (0 );
223- pto -> phcount = 0 ;
224- }
225- else {
226- pto -> args = pto_args ;
227- pto -> phcount = pto_phcount ;
228- Py_INCREF (pto_args );
229- assert (PyTuple_Check (pto -> args ));
230- }
226+ new_args = PyTuple_GetSlice (args , 1 , new_nargs + 1 );
227+ if (new_args == NULL ) {
228+ Py_DECREF (pto );
229+ return NULL ;
231230 }
232- else {
233- /* Count placeholders */
234- Py_ssize_t phcount = 0 ;
235- for (Py_ssize_t i = 0 ; i < new_nargs ; i ++ ) {
236- if (PyTuple_GET_ITEM (args , i + 1 ) == phold ) {
237- phcount ++ ;
238- }
231+
232+ /* Count placeholders */
233+ Py_ssize_t phcount = 0 ;
234+ for (Py_ssize_t i = 0 ; i < new_nargs - 1 ; i ++ ) {
235+ if (PyTuple_GET_ITEM (new_args , i ) == phold ) {
236+ phcount ++ ;
239237 }
240- if (pto_args == NULL ) {
241- new_args = PyTuple_GetSlice (args , 1 , new_nargs + 1 );
242- if (new_args == NULL ) {
243- Py_DECREF (pto );
244- return NULL ;
245- }
246- pto -> args = new_args ;
247- pto -> phcount = phcount ;
238+ }
239+ /* merge args with args of `func` which is `partial` */
240+ if (pto_phcount > 0 && new_nargs > 0 ) {
241+ Py_ssize_t npargs = PyTuple_GET_SIZE (pto_args );
242+ Py_ssize_t tot_nargs = npargs ;
243+ if (new_nargs > pto_phcount ) {
244+ tot_nargs += new_nargs - pto_phcount ;
248245 }
249- else {
250- /* merge args with args of `func` which is `partial` */
251- Py_ssize_t npargs = PyTuple_GET_SIZE (pto_args );
252- Py_ssize_t tot_nargs = npargs ;
253- if (new_nargs > pto_phcount ) {
254- tot_nargs += new_nargs - pto_phcount ;
255- }
256- PyObject * tot_args = PyTuple_New (tot_nargs );
257- PyObject * item ;
258- if (pto_phcount > 0 ) {
259- for (Py_ssize_t i = 0 , j = 0 ; i < tot_nargs ; ++ i ) {
260- if (i < npargs ) {
261- item = PyTuple_GET_ITEM (pto_args , i );
262- if (j < new_nargs && item == phold ) {
263- item = PyTuple_GET_ITEM (args , j + 1 );
264- j ++ ;
265- pto_phcount -- ;
266- }
267- }
268- else {
269- item = PyTuple_GET_ITEM (args , j + 1 );
270- j ++ ;
271- }
272- Py_INCREF (item );
273- PyTuple_SET_ITEM (tot_args , i , item );
246+ PyObject * item ;
247+ PyObject * tot_args = PyTuple_New (tot_nargs );
248+ for (Py_ssize_t i = 0 , j = 0 ; i < tot_nargs ; i ++ ) {
249+ if (i < npargs ) {
250+ item = PyTuple_GET_ITEM (pto_args , i );
251+ if (j < new_nargs && item == phold ) {
252+ item = PyTuple_GET_ITEM (new_args , j );
253+ j ++ ;
254+ pto_phcount -- ;
274255 }
275256 }
276257 else {
277- for (Py_ssize_t i = 0 ; i < npargs ; ++ i ) {
278- item = PyTuple_GET_ITEM (pto_args , i );
279- Py_INCREF (item );
280- PyTuple_SET_ITEM (tot_args , i , item );
281- }
282- for (Py_ssize_t i = 0 ; i < new_nargs ; ++ i ) {
283- item = PyTuple_GET_ITEM (args , i + 1 );
284- Py_INCREF (item );
285- PyTuple_SET_ITEM (tot_args , npargs + i , item );
286- }
258+ item = PyTuple_GET_ITEM (new_args , j );
259+ j ++ ;
287260 }
288- pto -> args = tot_args ;
289- pto -> phcount = pto_phcount + phcount ;
290- assert (PyTuple_Check (pto -> args ));
261+ Py_INCREF (item );
262+ PyTuple_SET_ITEM (tot_args , i , item );
291263 }
264+ pto -> args = tot_args ;
265+ pto -> phcount = pto_phcount + phcount ;
266+ Py_DECREF (new_args );
267+ }
268+ else if (pto_args == NULL ) {
269+ pto -> args = new_args ;
270+ pto -> phcount = phcount ;
271+ }
272+ else {
273+ pto -> args = PySequence_Concat (pto_args , new_args );
274+ pto -> phcount = pto_phcount + phcount ;
275+ Py_DECREF (new_args );
276+ if (pto -> args == NULL ) {
277+ Py_DECREF (pto );
278+ return NULL ;
279+ }
280+ assert (PyTuple_Check (pto -> args ));
292281 }
293282
294- /* process keywords */
295283 if (pto_kw == NULL || PyDict_GET_SIZE (pto_kw ) == 0 ) {
296284 if (kw == NULL ) {
297285 pto -> kw = PyDict_New ();
@@ -414,12 +402,6 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
414402 pto_args , pto_nargs , NULL );
415403 }
416404
417- /* Fast path if all Placeholders */
418- if (pto_nargs == pto_phcount ) {
419- return _PyObject_VectorcallTstate (tstate , pto -> fn ,
420- args , nargs , kwnames );
421- }
422-
423405 /* Fast path using PY_VECTORCALL_ARGUMENTS_OFFSET to prepend a single
424406 * positional argument */
425407 if (pto_nargs == 1 && (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET )) {
@@ -711,8 +693,14 @@ partial_setstate(PyObject *self, PyObject *state)
711693 return NULL ;
712694 }
713695
714- /* Count placeholders */
715696 Py_ssize_t nargs = PyTuple_GET_SIZE (fnargs );
697+ if (nargs && PyTuple_GET_ITEM (fnargs , nargs - 1 ) == pto -> placeholder ) {
698+ PyErr_SetString (PyExc_TypeError ,
699+ "trailing Placeholders are not allowed" );
700+ return NULL ;
701+ }
702+
703+ /* Count placeholders */
716704 Py_ssize_t phcount = 0 ;
717705 for (Py_ssize_t i = 0 ; i < nargs - 1 ; i ++ ) {
718706 if (PyTuple_GET_ITEM (fnargs , i ) == pto -> placeholder ) {
0 commit comments