@@ -196,8 +196,6 @@ def prepare_func_def(
196196 mapper : Mapper ,
197197 options : CompilerOptions ,
198198) -> FuncDecl :
199- create_generator_class_if_needed (module_name , class_name , fdef , mapper )
200-
201199 kind = (
202200 FUNC_CLASSMETHOD
203201 if fdef .is_class
@@ -209,38 +207,37 @@ def prepare_func_def(
209207 return decl
210208
211209
212- def create_generator_class_if_needed (
210+ def create_generator_class_for_func (
213211 module_name : str , class_name : str | None , fdef : FuncDef , mapper : Mapper , name_suffix : str = ""
214- ) -> None :
215- """If function is a generator/async function, declare a generator class.
212+ ) -> ClassIR :
213+ """For a generator/async function, declare a generator class.
216214
217215 Each generator and async function gets a dedicated class that implements the
218216 generator protocol with generated methods.
219217 """
220- if fdef .is_coroutine or fdef .is_generator :
221- name = "_" .join (x for x in [fdef .name , class_name ] if x ) + "_gen" + name_suffix
222- cir = ClassIR (name , module_name , is_generated = True , is_final_class = True )
223- cir .reuse_freed_instance = True
224- mapper .fdef_to_generator [fdef ] = cir
218+ assert fdef .is_coroutine or fdef .is_generator
219+ name = "_" .join (x for x in [fdef .name , class_name ] if x ) + "_gen" + name_suffix
220+ cir = ClassIR (name , module_name , is_generated = True , is_final_class = True )
221+ cir .reuse_freed_instance = True
222+ mapper .fdef_to_generator [fdef ] = cir
225223
226- helper_sig = FuncSignature (
227- (
228- RuntimeArg (SELF_NAME , object_rprimitive ),
229- RuntimeArg ("type" , object_rprimitive ),
230- RuntimeArg ("value" , object_rprimitive ),
231- RuntimeArg ("traceback" , object_rprimitive ),
232- RuntimeArg ("arg" , object_rprimitive ),
233- # If non-NULL, used to store return value instead of raising StopIteration(retv)
234- RuntimeArg ("stop_iter_ptr" , object_pointer_rprimitive ),
235- ),
236- object_rprimitive ,
237- )
224+ helper_sig = FuncSignature (
225+ (
226+ RuntimeArg (SELF_NAME , object_rprimitive ),
227+ RuntimeArg ("type" , object_rprimitive ),
228+ RuntimeArg ("value" , object_rprimitive ),
229+ RuntimeArg ("traceback" , object_rprimitive ),
230+ RuntimeArg ("arg" , object_rprimitive ),
231+ # If non-NULL, used to store return value instead of raising StopIteration(retv)
232+ RuntimeArg ("stop_iter_ptr" , object_pointer_rprimitive ),
233+ ),
234+ object_rprimitive ,
235+ )
238236
239- # The implementation of most generator functionality is behind this magic method.
240- helper_fn_decl = FuncDecl (
241- GENERATOR_HELPER_NAME , name , module_name , helper_sig , internal = True
242- )
243- cir .method_decls [helper_fn_decl .name ] = helper_fn_decl
237+ # The implementation of most generator functionality is behind this magic method.
238+ helper_fn_decl = FuncDecl (GENERATOR_HELPER_NAME , name , module_name , helper_sig , internal = True )
239+ cir .method_decls [helper_fn_decl .name ] = helper_fn_decl
240+ return cir
244241
245242
246243def prepare_method_def (
@@ -811,3 +808,22 @@ def registered_impl_from_possible_register_call(
811808 if isinstance (node , Decorator ):
812809 return RegisteredImpl (node .func , dispatch_type )
813810 return None
811+
812+
813+ def adjust_generator_classes_of_methods (mapper : Mapper ) -> None :
814+ """Make optimizations and adjustments to generated generator classes of methods.
815+
816+ This is a separate pass after type map has been built, since we need all classes
817+ to be processed to analyze class hierarchies.
818+ """
819+ for fdef , ir in mapper .func_to_decl .items ():
820+ if isinstance (fdef , FuncDef ) and (fdef .is_coroutine or fdef .is_generator ):
821+ gen_ir = create_generator_class_for_func (ir .module_name , ir .class_name , fdef , mapper )
822+ # TODO: We could probably support decorators sometimes (static and class method?)
823+ if not fdef .is_decorated :
824+ # Give a more precise type for generators, so that we can optimize
825+ # code that uses them. They return a generator object, which has a
826+ # specific class. Without this, the type would have to be 'object'.
827+ ir .sig .ret_type = RInstance (gen_ir )
828+ if ir .bound_sig :
829+ ir .bound_sig .ret_type = RInstance (gen_ir )
0 commit comments