Compile the yield-from/await sequence using SEND/END_SEND/CLEANUP_THROW. compiler_add_yield_from This generates: send: SEND exit SETUP_FINALLY fail (via exception table) YIELD_VALUE 1 POP_BLOCK (implicit) RESUME JUMP send fail: CLEANUP_THROW exit: END_SEND
(&mut self, is_await: bool)
| 7688 | /// exit: |
| 7689 | /// END_SEND |
| 7690 | fn compile_yield_from_sequence(&mut self, is_await: bool) -> CompileResult<BlockIdx> { |
| 7691 | let send_block = self.new_block(); |
| 7692 | let fail_block = self.new_block(); |
| 7693 | let exit_block = self.new_block(); |
| 7694 | |
| 7695 | // send: |
| 7696 | self.switch_to_block(send_block); |
| 7697 | emit!(self, Instruction::Send { delta: exit_block }); |
| 7698 | |
| 7699 | // SETUP_FINALLY fail - set up exception handler for YIELD_VALUE |
| 7700 | emit!(self, PseudoInstruction::SetupFinally { delta: fail_block }); |
| 7701 | self.push_fblock( |
| 7702 | FBlockType::TryExcept, // Use TryExcept for exception handler |
| 7703 | send_block, |
| 7704 | exit_block, |
| 7705 | )?; |
| 7706 | |
| 7707 | // YIELD_VALUE with arg=1 (yield-from/await mode - not wrapped for async gen) |
| 7708 | emit!(self, Instruction::YieldValue { arg: 1 }); |
| 7709 | |
| 7710 | // POP_BLOCK before RESUME |
| 7711 | emit!(self, PseudoInstruction::PopBlock); |
| 7712 | self.pop_fblock(FBlockType::TryExcept); |
| 7713 | |
| 7714 | // RESUME |
| 7715 | emit!( |
| 7716 | self, |
| 7717 | Instruction::Resume { |
| 7718 | context: if is_await { |
| 7719 | oparg::ResumeContext::from(oparg::ResumeLocation::AfterAwait) |
| 7720 | } else { |
| 7721 | oparg::ResumeContext::from(oparg::ResumeLocation::AfterYieldFrom) |
| 7722 | } |
| 7723 | } |
| 7724 | ); |
| 7725 | |
| 7726 | // JUMP_BACKWARD_NO_INTERRUPT send |
| 7727 | emit!( |
| 7728 | self, |
| 7729 | PseudoInstruction::JumpNoInterrupt { delta: send_block } |
| 7730 | ); |
| 7731 | |
| 7732 | // fail: CLEANUP_THROW |
| 7733 | // Stack when exception: [receiver, yielded_value, exc] |
| 7734 | // CLEANUP_THROW: [sub_iter, last_sent_val, exc] -> [None, value] |
| 7735 | // After: stack is [None, value], fall through to exit |
| 7736 | self.switch_to_block(fail_block); |
| 7737 | emit!(self, Instruction::CleanupThrow); |
| 7738 | // Fall through to exit block |
| 7739 | |
| 7740 | // exit: END_SEND |
| 7741 | // Stack: [receiver, value] (from SEND) or [None, value] (from CLEANUP_THROW) |
| 7742 | // END_SEND: [receiver/None, value] -> [value] |
| 7743 | self.switch_to_block(exit_block); |
| 7744 | emit!(self, Instruction::EndSend); |
| 7745 | |
| 7746 | Ok(send_block) |
| 7747 | } |
no test coverage detected