py/vm: Fix case of handling raised StopIteration within yield from.
This patch concerns the handling of an NLR-raised StopIteration, raised during a call to mp_resume() which is handling the yield from opcode. Previously, commit6738c1dded
introduced code to handle this case, along with a test. It seems that it was lucky that the test worked because the code did not correctly handle the stack pointer (sp). Furthermore, commit79d996a57b
improved the way mp_resume() propagated certain exceptions: it changed raising an NLR value to returning MP_VM_RETURN_EXCEPTION. This change meant that the test introduced in gen_yield_from_ducktype.py was no longer hitting the code introduced in6738c1dded
. The patch here does two things: 1. Fixes the handling of sp in the VM for the case that yield from is interrupted by a StopIteration raised via NLR. 2. Introduces a new test to check this handling of sp and re-covers the code in the VM.
This commit is contained in:
parent
c5fe610ba1
commit
22ade2f5c4
4
py/vm.c
4
py/vm.c
|
@ -1162,6 +1162,7 @@ yield:
|
|||
mp_obj_t send_value = POP();
|
||||
mp_obj_t t_exc = MP_OBJ_NULL;
|
||||
mp_obj_t ret_value;
|
||||
code_state->sp = sp; // Save sp because it's needed if mp_resume raises StopIteration
|
||||
if (inject_exc != MP_OBJ_NULL) {
|
||||
t_exc = inject_exc;
|
||||
inject_exc = MP_OBJ_NULL;
|
||||
|
@ -1361,7 +1362,8 @@ exception_handler:
|
|||
} else if (*code_state->ip == MP_BC_YIELD_FROM) {
|
||||
// StopIteration inside yield from call means return a value of
|
||||
// yield from, so inject exception's value as yield from's result
|
||||
*++code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val));
|
||||
// (Instead of stack pop then push we just replace exhausted gen with value)
|
||||
*code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val));
|
||||
code_state->ip++; // yield from is over, move to next instruction
|
||||
goto outer_dispatch_loop; // continue with dispatch loop
|
||||
}
|
||||
|
|
|
@ -40,3 +40,16 @@ def gen6():
|
|||
|
||||
g = gen6()
|
||||
print(list(g))
|
||||
|
||||
# StopIteration from within a Python function, within a native iterator (map), within a yield from
|
||||
def gen7(x):
|
||||
if x < 3:
|
||||
return x
|
||||
else:
|
||||
raise StopIteration(444)
|
||||
|
||||
def gen8():
|
||||
print((yield from map(gen7, range(100))))
|
||||
|
||||
g = gen8()
|
||||
print(list(g))
|
||||
|
|
Loading…
Reference in New Issue