diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 56a54b002df773f..b7b47a5b1e9d182 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -269,10 +269,22 @@ def loop(): loop() def test_issue125038(self): - g = (x for x in range(10)) - g.gi_frame.f_locals['.0'] = range(20) - l = list(g) - self.assertListEqual(l, []) + def get_generator(): + g = (x for x in range(10)) + g.gi_frame.f_locals['.0'] = range(20) + return g + + def genexpr_to_list(): + try: + l = list(get_generator()) + return "NoError" + except TypeError: + return "TypeError" + + # This should not raise + r = genexpr_to_list() + + self.assertIs(r, "TypeError") class ExceptionTest(unittest.TestCase): # Tests for the issue #23353: check that the currently handled exception diff --git a/Python/bytecodes.c b/Python/bytecodes.c index c374091abe62ae5..7770b2f047c8a9f 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2804,10 +2804,16 @@ dummy_func( replaced op(_FOR_ITER, (iter -- iter, next)) { /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); - PyObject *next_o = NULL; - if (PyIter_Check(iter_o)) { - next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); + PyTypeObject *type = Py_TYPE(iter_o); + iternextfunc iternext = type->tp_iternext; + if (iternext == NULL) { + _PyErr_Format(tstate, PyExc_TypeError, + "'for' requires an object with " + "__iter__ method, got %.100s", + type->tp_name); + ERROR_NO_POP(); } + PyObject *next_o = (*iternext)(iter_o); if (next_o == NULL) { if (_PyErr_Occurred(tstate)) { int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration); @@ -2833,10 +2839,16 @@ dummy_func( op(_FOR_ITER_TIER_TWO, (iter -- iter, next)) { /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); - PyObject *next_o = NULL; - if (PyIter_Check(iter_o)) { - next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); + PyTypeObject *type = Py_TYPE(iter_o); + iternextfunc iternext = type->tp_iternext; + if (iternext == NULL) { + _PyErr_Format(tstate, PyExc_TypeError, + "'for' requires an object with " + "__iter__ method, got %.100s", + type->tp_name); + ERROR_NO_POP(); } + PyObject *next_o = (*iternext)(iter_o); if (next_o == NULL) { if (_PyErr_Occurred(tstate)) { int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration); @@ -2860,10 +2872,16 @@ dummy_func( _Py_CODEUNIT *target; _PyStackRef iter_stackref = TOP(); PyObject *iter = PyStackRef_AsPyObjectBorrow(iter_stackref); - PyObject *next = NULL; - if (PyIter_Check(iter)) { - next = (*Py_TYPE(iter)->tp_iternext)(iter); + PyTypeObject *type = Py_TYPE(iter); + iternextfunc iternext = type->tp_iternext; + if (iternext == NULL) { + _PyErr_Format(tstate, PyExc_TypeError, + "'for' requires an object with " + "__iter__ method, got %.100s", + type->tp_name); + ERROR_NO_POP(); } + PyObject *next = (*iternext)(iter); if (next != NULL) { PUSH(PyStackRef_FromPyObjectSteal(next)); target = next_instr; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 7aa3b25df3a1255..1394e413fdaf585 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3336,12 +3336,20 @@ iter = stack_pointer[-1]; /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); - PyObject *next_o = NULL; - if (PyIter_Check(iter_o)) { + PyTypeObject *type = Py_TYPE(iter_o); + iternextfunc iternext = type->tp_iternext; + if (iternext == NULL) { _PyFrame_SetStackPointer(frame, stack_pointer); - next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); + _PyErr_Format(tstate, PyExc_TypeError, + "'for' requires an object with " + "__iter__ method, got %.100s", + type->tp_name); stack_pointer = _PyFrame_GetStackPointer(frame); + JUMP_TO_ERROR(); } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *next_o = (*iternext)(iter_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (next_o == NULL) { if (_PyErr_Occurred(tstate)) { _PyFrame_SetStackPointer(frame, stack_pointer); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index b13315350d05145..a53800d0d6ae7fb 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3920,12 +3920,20 @@ { /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); - PyObject *next_o = NULL; - if (PyIter_Check(iter_o)) { + PyTypeObject *type = Py_TYPE(iter_o); + iternextfunc iternext = type->tp_iternext; + if (iternext == NULL) { _PyFrame_SetStackPointer(frame, stack_pointer); - next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); + _PyErr_Format(tstate, PyExc_TypeError, + "'for' requires an object with " + "__iter__ method, got %.100s", + type->tp_name); stack_pointer = _PyFrame_GetStackPointer(frame); + goto error; } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *next_o = (*iternext)(iter_o); + stack_pointer = _PyFrame_GetStackPointer(frame); if (next_o == NULL) { if (_PyErr_Occurred(tstate)) { _PyFrame_SetStackPointer(frame, stack_pointer); @@ -4615,12 +4623,20 @@ _Py_CODEUNIT *target; _PyStackRef iter_stackref = TOP(); PyObject *iter = PyStackRef_AsPyObjectBorrow(iter_stackref); - PyObject *next = NULL; - if (PyIter_Check(iter)) { + PyTypeObject *type = Py_TYPE(iter); + iternextfunc iternext = type->tp_iternext; + if (iternext == NULL) { _PyFrame_SetStackPointer(frame, stack_pointer); - next = (*Py_TYPE(iter)->tp_iternext)(iter); + _PyErr_Format(tstate, PyExc_TypeError, + "'for' requires an object with " + "__iter__ method, got %.100s", + type->tp_name); stack_pointer = _PyFrame_GetStackPointer(frame); + goto error; } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *next = (*iternext)(iter); + stack_pointer = _PyFrame_GetStackPointer(frame); if (next != NULL) { PUSH(PyStackRef_FromPyObjectSteal(next)); target = next_instr;