diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 9163d1a4421a8c..5a62193185e126 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1313,13 +1313,23 @@ iterations of the loop. .. versionadded:: 3.11 -.. opcode:: SEND +.. opcode:: SEND (delta) - Sends ``None`` to the sub-generator of this generator. - Used in ``yield from`` and ``await`` statements. + Equivalent to ``TOS = TOS1.send(TOS)``. Used in ``yield from`` and ``await`` + statements. + + If the call raises :exc:`StopIteration`, pop both values, push its return + value, and increment the bytecode counter by *delta*. + + If TOS1 is ``NULL`` (set when a ``throw()`` through the current frame + returns), pop both values, push TOS (its return value) back, and increment + the bytecode counter by *delta*. .. versionadded:: 3.11 + .. versionchanged:: 3.12 + Added ``NULL`` handling for subiterators that return during ``throw()``. + .. opcode:: ASYNC_GEN_WRAP diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-17-11-40-20.bpo-46841.cU7e6B.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-17-11-40-20.bpo-46841.cU7e6B.rst new file mode 100644 index 00000000000000..a71ba26c107d55 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-17-11-40-20.bpo-46841.cU7e6B.rst @@ -0,0 +1,3 @@ +When a sub-iterator returns a value during a ``throw()`` call, perform the +resulting jump during the next :opcode:`SEND` instruction (rather than as +part of the ``throw()`` implementation). diff --git a/Objects/genobject.c b/Objects/genobject.c index 2b45e28cbf16df..fdfd9894a22706 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -491,14 +491,8 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, ret = _PyFrame_StackPop((_PyInterpreterFrame *)gen->gi_iframe); assert(ret == yf); Py_DECREF(ret); - // XXX: Performing this jump ourselves is awkward and problematic. - // See https://github.com/python/cpython/pull/31968. - /* Termination repetition of SEND loop */ - assert(_PyInterpreterFrame_LASTI(frame) >= 0); - /* Backup to SEND */ - assert(_Py_OPCODE(frame->prev_instr[-1]) == SEND); - int jump = _Py_OPARG(frame->prev_instr[-1]); - frame->prev_instr += jump - 1; + // NULL tells SEND to quit sending: + _PyFrame_StackPush((_PyInterpreterFrame *)gen->gi_iframe, NULL); if (_PyGen_FetchStopIterationValue(&val) == 0) { ret = gen_send(gen, val); Py_DECREF(val); diff --git a/Python/ceval.c b/Python/ceval.c index 0e8186347cd895..7ff650f81397f5 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2591,6 +2591,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int assert(STACK_LEVEL() >= 2); PyObject *v = POP(); PyObject *receiver = TOP(); + if (receiver == NULL) { + // Receiver returned during a throw(). v is its return value: + SET_TOP(v); + JUMPBY(oparg); + DISPATCH(); + } PySendResult gen_status; PyObject *retval; if (tstate->c_tracefunc == NULL) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy