|
15 | 15 | from mypyc.common import SELF_NAME, NEXT_LABEL_ATTR_NAME, ENV_ATTR_NAME
|
16 | 16 | from mypyc.ir.ops import (
|
17 | 17 | BasicBlock, Call, Return, Goto, Integer, SetAttr, Unreachable, RaiseStandardError,
|
18 |
| - Value, Register |
| 18 | + Value, Register, MethodCall, TupleSet, Branch, NO_TRACEBACK_LINE_NO |
19 | 19 | )
|
20 | 20 | from mypyc.ir.rtypes import RInstance, int_rprimitive, object_rprimitive
|
21 | 21 | from mypyc.ir.func_ir import FuncIR, FuncDecl, FuncSignature, RuntimeArg
|
22 | 22 | from mypyc.ir.class_ir import ClassIR
|
23 |
| -from mypyc.primitives.exc_ops import raise_exception_with_tb_op |
| 23 | +from mypyc.irbuild.nonlocalcontrol import ExceptNonlocalControl |
| 24 | +from mypyc.primitives.exc_ops import ( |
| 25 | + raise_exception_with_tb_op, error_catch_op, exc_matches_op, reraise_exception_op, |
| 26 | + restore_exc_info_op |
| 27 | +) |
24 | 28 | from mypyc.irbuild.env_class import (
|
25 | 29 | add_args_to_env, load_outer_env, load_env_registers, finalize_env_class
|
26 | 30 | )
|
@@ -220,11 +224,46 @@ def add_throw_to_generator_class(builder: IRBuilder,
|
220 | 224 |
|
221 | 225 | def add_close_to_generator_class(builder: IRBuilder, fn_info: FuncInfo) -> None:
|
222 | 226 | """Generates the '__close__' method for a generator class."""
|
223 |
| - # TODO: Currently this method just triggers a runtime error. |
224 |
| - # We should fill this out (https://github.com/mypyc/mypyc/issues/790). |
225 | 227 | with builder.enter_method(fn_info.generator_class.ir, 'close', object_rprimitive, fn_info):
|
| 228 | + except_block, else_block = BasicBlock(), BasicBlock() |
| 229 | + builder.builder.push_error_handler(except_block) |
| 230 | + builder.goto_and_activate(BasicBlock()) |
| 231 | + generator_exit = builder.load_module_attr_by_fullname('builtins.GeneratorExit', |
| 232 | + fn_info.fitem.line) |
| 233 | + builder.add(MethodCall( |
| 234 | + builder.self(), |
| 235 | + 'throw', |
| 236 | + [generator_exit, builder.none_object(), builder.none_object()])) |
| 237 | + builder.goto(else_block) |
| 238 | + builder.builder.pop_error_handler() |
| 239 | + |
| 240 | + builder.activate_block(except_block) |
| 241 | + old_exc = builder.call_c(error_catch_op, [], fn_info.fitem.line) |
| 242 | + builder.nonlocal_control.append( |
| 243 | + ExceptNonlocalControl(builder.nonlocal_control[-1], old_exc)) |
| 244 | + stop_iteration = builder.load_module_attr_by_fullname('builtins.StopIteration', |
| 245 | + fn_info.fitem.line) |
| 246 | + exceptions = builder.add( |
| 247 | + TupleSet([generator_exit, stop_iteration], fn_info.fitem.line)) |
| 248 | + matches = builder.call_c( |
| 249 | + exc_matches_op, [exceptions], fn_info.fitem.line) |
| 250 | + |
| 251 | + match_block, non_match_block = BasicBlock(), BasicBlock() |
| 252 | + builder.add(Branch(matches, match_block, non_match_block, Branch.BOOL)) |
| 253 | + |
| 254 | + builder.activate_block(match_block) |
| 255 | + builder.call_c(restore_exc_info_op, [builder.read(old_exc)], fn_info.fitem.line) |
| 256 | + builder.add(Return(builder.none_object())) |
| 257 | + |
| 258 | + builder.activate_block(non_match_block) |
| 259 | + builder.call_c(reraise_exception_op, [], NO_TRACEBACK_LINE_NO) |
| 260 | + builder.add(Unreachable()) |
| 261 | + |
| 262 | + builder.nonlocal_control.pop() |
| 263 | + |
| 264 | + builder.activate_block(else_block) |
226 | 265 | builder.add(RaiseStandardError(RaiseStandardError.RUNTIME_ERROR,
|
227 |
| - 'close method on generator classes unimplemented', |
| 266 | + 'generator ignored GeneratorExit', |
228 | 267 | fn_info.fitem.line))
|
229 | 268 | builder.add(Unreachable())
|
230 | 269 |
|
|
0 commit comments