Make optimizations and adjustments to generated generator classes of methods. This is a separate pass after type map has been built, since we need all classes to be processed to analyze class hierarchies.
(mapper: Mapper)
| 891 | |
| 892 | |
| 893 | def adjust_generator_classes_of_methods(mapper: Mapper) -> None: |
| 894 | """Make optimizations and adjustments to generated generator classes of methods. |
| 895 | |
| 896 | This is a separate pass after type map has been built, since we need all classes |
| 897 | to be processed to analyze class hierarchies. |
| 898 | """ |
| 899 | |
| 900 | generator_methods = [] |
| 901 | |
| 902 | for fdef, fn_ir in mapper.func_to_decl.items(): |
| 903 | if isinstance(fdef, FuncDef) and (fdef.is_coroutine or fdef.is_generator): |
| 904 | gen_ir = create_generator_class_for_func( |
| 905 | fn_ir.module_name, fn_ir.class_name, fdef, mapper |
| 906 | ) |
| 907 | # TODO: We could probably support decorators sometimes (static and class method?) |
| 908 | if not fdef.is_decorated: |
| 909 | name = fn_ir.name |
| 910 | precise_ret_type = True |
| 911 | if fn_ir.class_name is not None: |
| 912 | class_ir = mapper.type_to_ir[fdef.info] |
| 913 | subcls = class_ir.subclasses() |
| 914 | if subcls is None: |
| 915 | # Override could be of a different type, so we can't make assumptions. |
| 916 | precise_ret_type = False |
| 917 | elif class_ir.is_trait: |
| 918 | # Give up on traits. We could possibly have an abstract base class |
| 919 | # for generator return types to make this use precise types. |
| 920 | precise_ret_type = False |
| 921 | else: |
| 922 | for s in subcls: |
| 923 | if name in s.method_decls: |
| 924 | m = s.method_decls[name] |
| 925 | if ( |
| 926 | m.is_generator != fn_ir.is_generator |
| 927 | or m.is_coroutine != fn_ir.is_coroutine |
| 928 | ): |
| 929 | # Override is of a different kind, and the optimization |
| 930 | # to use a precise generator return type doesn't work. |
| 931 | precise_ret_type = False |
| 932 | else: |
| 933 | class_ir = None |
| 934 | |
| 935 | if precise_ret_type: |
| 936 | # Give a more precise type for generators, so that we can optimize |
| 937 | # code that uses them. They return a generator object, which has a |
| 938 | # specific class. Without this, the type would have to be 'object'. |
| 939 | fn_ir.sig.ret_type = RInstance(gen_ir) |
| 940 | if fn_ir.bound_sig: |
| 941 | fn_ir.bound_sig.ret_type = RInstance(gen_ir) |
| 942 | if class_ir is not None: |
| 943 | if class_ir.is_method_final(name): |
| 944 | gen_ir.is_final_class = True |
| 945 | generator_methods.append((name, class_ir, gen_ir)) |
| 946 | |
| 947 | new_bases = {} |
| 948 | |
| 949 | for name, class_ir, gen in generator_methods: |
| 950 | # For generator methods, we need to have subclass generator classes inherit from |
no test coverage detected
searching dependent graphs…