82
82
@ CoreFunctions (extendClasses = PythonBuiltinClassType .PGenerator )
83
83
public class GeneratorBuiltins extends PythonBuiltins {
84
84
85
+ /**
86
+ * Creates a fresh copy of the generator arguments to be used for the next invocation of the
87
+ * generator. This is necessary to avoid persisting caller state. For example: If the generator
88
+ * is invoked using {@code next(g)} outside of any {@code except} handler but the generator
89
+ * requests the exception state, then the exception state will be written into the arguments. If
90
+ * we now use the same arguments array every time, the next invocation would think that there is
91
+ * not excepion but in fact, the a subsequent call ot {@code next} may have a different
92
+ * exception state.
93
+ *
94
+ * <pre>
95
+ * g = my_generator()
96
+ *
97
+ * # invoke without any exception context
98
+ * next(g)
99
+ *
100
+ * try:
101
+ * raise ValueError
102
+ * except ValueError:
103
+ * # invoke with exception context
104
+ * next(g)
105
+ * </pre>
106
+ *
107
+ * This is necessary for correct chaining of exceptions.
108
+ */
109
+ private static Object [] prepareArguments (PGenerator self ) {
110
+ Object [] generatorArguments = self .getArguments ();
111
+ Object [] arguments = new Object [generatorArguments .length ];
112
+ PythonUtils .arraycopy (generatorArguments , 0 , arguments , 0 , arguments .length );
113
+ return arguments ;
114
+ }
115
+
85
116
private static Object resumeGenerator (PGenerator self ) {
86
117
try {
87
- return self .getCurrentCallTarget ().call (self . getArguments ( ));
118
+ return self .getCurrentCallTarget ().call (prepareArguments ( self ));
88
119
} catch (PException e ) {
89
120
self .markAsFinished ();
90
121
throw e ;
@@ -133,8 +164,7 @@ public Object nextCached(VirtualFrame frame, PGenerator self,
133
164
throw raise (StopIteration );
134
165
}
135
166
try {
136
- Object [] arguments = self .getArguments ();
137
- return call .execute (frame , null , null , arguments );
167
+ return call .execute (frame , null , null , prepareArguments (self ));
138
168
} catch (PException e ) {
139
169
self .markAsFinished ();
140
170
throw e ;
@@ -150,8 +180,7 @@ public Object next(VirtualFrame frame, PGenerator self,
150
180
throw raise (StopIteration );
151
181
}
152
182
try {
153
- Object [] arguments = self .getArguments ();
154
- return call .execute (frame , self .getCurrentCallTarget (), arguments );
183
+ return call .execute (frame , self .getCurrentCallTarget (), prepareArguments (self ));
155
184
} catch (PException e ) {
156
185
self .markAsFinished ();
157
186
throw e ;
0 commit comments