From 809d89c794ceb44760ab997ff9a496488b4a2c0c Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 30 Sep 2019 16:06:20 +1000 Subject: [PATCH] py/runtime: Fix PEP479 behaviour throwing StopIteration into yield from. Commit 3f6ffe059f64b3ebc44dc0bbc63452cb8850702b implemented PEP479 but did not catch the case fixed in this commit. Found by coverage analysis, that the VM had uncovered code. --- py/runtime.c | 7 ++++++- py/vm.c | 11 ++--------- tests/basics/generator_pep479.py | 11 +++++++++++ tests/basics/generator_pep479.py.exp | 2 ++ 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index 2657e7cc25..6b7a9ce3c6 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1319,7 +1319,12 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th // will be propagated up. This behavior is approved by test_pep380.py // test_delegation_of_close_to_non_generator(), // test_delegating_throw_to_non_generator() - *ret_val = mp_make_raise_obj(throw_value); + if (mp_obj_exception_match(throw_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + // PEP479: if StopIteration is raised inside a generator it is replaced with RuntimeError + *ret_val = mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator raised StopIteration"); + } else { + *ret_val = mp_make_raise_obj(throw_value); + } return MP_VM_RETURN_EXCEPTION; } } diff --git a/py/vm.c b/py/vm.c index 6e5015fc43..7c702f3863 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1266,17 +1266,10 @@ yield: DISPATCH(); } else { assert(ret_kind == MP_VM_RETURN_EXCEPTION); + assert(!EXC_MATCH(ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))); // Pop exhausted gen sp--; - if (EXC_MATCH(ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { - PUSH(mp_obj_exception_get_value(ret_value)); - // If we injected GeneratorExit downstream, then even - // if it was swallowed, we re-raise GeneratorExit - GENERATOR_EXIT_IF_NEEDED(t_exc); - DISPATCH(); - } else { - RAISE(ret_value); - } + RAISE(ret_value); } } diff --git a/tests/basics/generator_pep479.py b/tests/basics/generator_pep479.py index e422c349e7..5385312170 100644 --- a/tests/basics/generator_pep479.py +++ b/tests/basics/generator_pep479.py @@ -27,3 +27,14 @@ try: g.throw(StopIteration) except RuntimeError: print('RuntimeError') + +# throwing a StopIteration through yield from, will be converted to a RuntimeError +def gen(): + yield from range(2) + print('should not get here') +g = gen() +print(next(g)) +try: + g.throw(StopIteration) +except RuntimeError: + print('RuntimeError') diff --git a/tests/basics/generator_pep479.py.exp b/tests/basics/generator_pep479.py.exp index c64fe49561..6101339462 100644 --- a/tests/basics/generator_pep479.py.exp +++ b/tests/basics/generator_pep479.py.exp @@ -3,3 +3,5 @@ RuntimeError StopIteration 1 RuntimeError +0 +RuntimeError