(self, builder: IRBuilder, value: Value, line: int)
| 90 | """Default nonlocal control in a generator function outside statements.""" |
| 91 | |
| 92 | def gen_return(self, builder: IRBuilder, value: Value, line: int) -> None: |
| 93 | # Assign an invalid next label number so that the next time |
| 94 | # __next__ is called, we jump to the case in which |
| 95 | # StopIteration is raised. |
| 96 | builder.assign(builder.fn_info.generator_class.next_label_target, Integer(-1), line) |
| 97 | |
| 98 | # Raise a StopIteration containing a field for the value that |
| 99 | # should be returned. Before doing so, create a new block |
| 100 | # without an error handler set so that the implicitly thrown |
| 101 | # StopIteration isn't caught by except blocks inside of the |
| 102 | # generator function. |
| 103 | builder.builder.push_error_handler(None) |
| 104 | builder.goto_and_activate(BasicBlock()) |
| 105 | |
| 106 | # Skip creating a traceback frame when we raise here, because |
| 107 | # we don't care about the traceback frame and it is kind of |
| 108 | # expensive since raising StopIteration is an extremely common |
| 109 | # case. Also we call a special internal function to set |
| 110 | # StopIteration instead of using RaiseStandardError because |
| 111 | # the obvious thing doesn't work if the value is a tuple |
| 112 | # (???). |
| 113 | |
| 114 | true, false = BasicBlock(), BasicBlock() |
| 115 | stop_iter_reg = builder.fn_info.generator_class.stop_iter_value_reg |
| 116 | assert stop_iter_reg is not None |
| 117 | |
| 118 | builder.add(Branch(stop_iter_reg, true, false, Branch.IS_ERROR)) |
| 119 | |
| 120 | builder.activate_block(true) |
| 121 | # The default/slow path is to raise a StopIteration exception with |
| 122 | # return value. |
| 123 | builder.call_c(set_stop_iteration_value, [value], NO_TRACEBACK_LINE_NO) |
| 124 | builder.add(Unreachable()) |
| 125 | builder.builder.pop_error_handler() |
| 126 | |
| 127 | builder.activate_block(false) |
| 128 | # The fast path is to store return value via caller-provided pointer |
| 129 | # instead of raising an exception. This can only be used when the |
| 130 | # caller is a native function. |
| 131 | builder.add(SetMem(object_rprimitive, stop_iter_reg, value)) |
| 132 | builder.add(Return(Integer(0, object_rprimitive))) |
| 133 | |
| 134 | |
| 135 | class CleanupNonlocalControl(NonlocalControl): |
nothing calls this directly
no test coverage detected