Skip to content

Commit 7344285

Browse files
Issue #28257: Improved error message when pass a non-iterable as
a var-positional argument. Added opcode BUILD_TUPLE_UNPACK_WITH_CALL.
1 parent 8f0f205 commit 7344285

File tree

9 files changed

+140
-113
lines changed

9 files changed

+140
-113
lines changed

Include/opcode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ extern "C" {
125125
#define FORMAT_VALUE 155
126126
#define BUILD_CONST_KEY_MAP 156
127127
#define BUILD_STRING 157
128+
#define BUILD_TUPLE_UNPACK_WITH_CALL 158
128129

129130
/* EXCEPT_HANDLER is a special, implicit block type which is created when
130131
entering an except handler. It is not an opcode but we define it here

Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ def _write_atomic(path, data, mode=0o666):
238238
# #27985)
239239
# Python 3.6b1 3376 (simplify CALL_FUNCTIONs & BUILD_MAP_UNPACK_WITH_CALL)
240240
# Python 3.6b1 3377 (set __class__ cell from type.__new__ #23722)
241+
# Python 3.6b2 3378 (add BUILD_TUPLE_UNPACK_WITH_CALL #28257)
241242
#
242243
# MAGIC must change whenever the bytecode emitted by the compiler may no
243244
# longer be understood by older implementations of the eval loop (usually
@@ -246,7 +247,7 @@ def _write_atomic(path, data, mode=0o666):
246247
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
247248
# in PC/launcher.c must also be updated.
248249

249-
MAGIC_NUMBER = (3377).to_bytes(2, 'little') + b'\r\n'
250+
MAGIC_NUMBER = (3378).to_bytes(2, 'little') + b'\r\n'
250251
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
251252

252253
_PYCACHE = '__pycache__'

Lib/opcode.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,6 @@ def jabs_op(name, op):
196196
def_op('LOAD_CLASSDEREF', 148)
197197
hasfree.append(148)
198198

199-
jrel_op('SETUP_ASYNC_WITH', 154)
200-
201199
def_op('EXTENDED_ARG', 144)
202200
EXTENDED_ARG = 144
203201

@@ -207,8 +205,11 @@ def jabs_op(name, op):
207205
def_op('BUILD_TUPLE_UNPACK', 152)
208206
def_op('BUILD_SET_UNPACK', 153)
209207

208+
jrel_op('SETUP_ASYNC_WITH', 154)
209+
210210
def_op('FORMAT_VALUE', 155)
211211
def_op('BUILD_CONST_KEY_MAP', 156)
212212
def_op('BUILD_STRING', 157)
213+
def_op('BUILD_TUPLE_UNPACK_WITH_CALL', 158)
213214

214215
del def_op, name_op, jrel_op, jabs_op

Lib/test/test_extcall.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,16 @@
233233
...
234234
TypeError: h() argument after * must be an iterable, not function
235235
236+
>>> h(1, *h)
237+
Traceback (most recent call last):
238+
...
239+
TypeError: h() argument after * must be an iterable, not function
240+
241+
>>> h(*[1], *h)
242+
Traceback (most recent call last):
243+
...
244+
TypeError: h() argument after * must be an iterable, not function
245+
236246
>>> dir(*h)
237247
Traceback (most recent call last):
238248
...

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ Core and Builtins
4646
Library
4747
-------
4848

49+
- Issue #28257: Improved error message when pass a non-iterable as
50+
a var-positional argument. Added opcode BUILD_TUPLE_UNPACK_WITH_CALL.
51+
4952
- Issue #28322: Fixed possible crashes when unpickle itertools objects from
5053
incorrect pickle data. Based on patch by John Leitch.
5154

Python/ceval.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2509,9 +2509,10 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
25092509
DISPATCH();
25102510
}
25112511

2512+
TARGET(BUILD_TUPLE_UNPACK_WITH_CALL)
25122513
TARGET(BUILD_TUPLE_UNPACK)
25132514
TARGET(BUILD_LIST_UNPACK) {
2514-
int convert_to_tuple = opcode == BUILD_TUPLE_UNPACK;
2515+
int convert_to_tuple = opcode != BUILD_LIST_UNPACK;
25152516
Py_ssize_t i;
25162517
PyObject *sum = PyList_New(0);
25172518
PyObject *return_value;
@@ -2524,6 +2525,16 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
25242525

25252526
none_val = _PyList_Extend((PyListObject *)sum, PEEK(i));
25262527
if (none_val == NULL) {
2528+
if (opcode == BUILD_TUPLE_UNPACK_WITH_CALL &&
2529+
PyErr_ExceptionMatches(PyExc_TypeError)) {
2530+
PyObject *func = PEEK(1 + oparg);
2531+
PyErr_Format(PyExc_TypeError,
2532+
"%.200s%.200s argument after * "
2533+
"must be an iterable, not %.200s",
2534+
PyEval_GetFuncName(func),
2535+
PyEval_GetFuncDesc(func),
2536+
PEEK(i)->ob_type->tp_name);
2537+
}
25272538
Py_DECREF(sum);
25282539
goto error;
25292540
}

Python/compile.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -987,9 +987,9 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
987987
return 1-oparg;
988988
case BUILD_LIST_UNPACK:
989989
case BUILD_TUPLE_UNPACK:
990+
case BUILD_TUPLE_UNPACK_WITH_CALL:
990991
case BUILD_SET_UNPACK:
991992
case BUILD_MAP_UNPACK:
992-
return 1 - oparg;
993993
case BUILD_MAP_UNPACK_WITH_CALL:
994994
return 1 - oparg;
995995
case BUILD_MAP:
@@ -3549,7 +3549,7 @@ compiler_call_helper(struct compiler *c,
35493549
if (nsubargs > 1) {
35503550
/* If we ended up with more than one stararg, we need
35513551
to concatenate them into a single sequence. */
3552-
ADDOP_I(c, BUILD_TUPLE_UNPACK, nsubargs);
3552+
ADDOP_I(c, BUILD_TUPLE_UNPACK_WITH_CALL, nsubargs);
35533553
}
35543554
else if (nsubargs == 0) {
35553555
ADDOP_I(c, BUILD_TUPLE, 0);

0 commit comments

Comments
 (0)