use super::{ConstValue, LoopBuilder, ValueId}; use crate::mir::BasicBlockId; /// ループ脱出の種類(箱化・共通化のための型) #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(super) enum LoopExitKind { /// break文(exit blockへジャンプ) Break, /// continue文(header blockへジャンプ) Continue, } impl<'a> LoopBuilder<'a> { /// Emit a jump to `target` from the current block and record predecessor metadata. fn jump_with_pred(&mut self, target: BasicBlockId) -> Result<(), String> { let cur_block = self.current_block()?; self.emit_jump(target)?; let _ = crate::mir::builder::loops::add_predecessor(self.parent_builder, target, cur_block); Ok(()) } /// [LoopForm] 【箱化】ループ脱出の共通処理(break/continue統一化) /// /// Phase 25.1o: break と continue の共通パターンを抽出し、 /// LoopExitKind で振る舞いを切り替える統一メソッド。 /// /// # 処理フロー /// 1. 現在の変数マップをスナップショット /// 2. [LoopForm] スナップショット保存(Break → exit_snapshots, Continue → continue_snapshots) /// 3. Void を定義(戻り値用のダミー) /// 4. [LoopForm] ターゲットブロックへジャンプ(Break → exit, Continue → header/continue_merge) /// 5. 現在ブロックはジャンプで終端済みのまま維持(新しい unreachable ブロックは作らない) fn do_loop_exit(&mut self, kind: LoopExitKind) -> Result { // 1. スナップショット取得(共通処理) let snapshot = self.get_current_variable_map(); let cur_block = self.current_block()?; // 2. [LoopForm] exit-break path: スナップショット保存(exit PHI入力用) // [LoopForm] continue-backedge path: スナップショット保存(continue_merge → header) match kind { LoopExitKind::Break => { if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() { eprintln!( "[DEBUG/do_break] Saved snapshot from block {:?}, vars: {:?}", cur_block, snapshot.keys().collect::>() ); } self.exit_snapshots.push((cur_block, snapshot)); } LoopExitKind::Continue => { self.block_var_maps.insert(cur_block, snapshot.clone()); self.continue_snapshots.push((cur_block, snapshot)); } } // 3. 戻り値用のダミーを定義(現在ブロック内で完結させる) let void_id = self.new_value(); self.emit_const(void_id, ConstValue::Void)?; // 4. ターゲットブロックへジャンプ(kind別処理) match kind { LoopExitKind::Break => { if let Some(exit_bb) = crate::mir::builder::loops::current_exit(self.parent_builder) { self.jump_with_pred(exit_bb)?; } } LoopExitKind::Continue => { // 既定では header にジャンプするが、canonical continue merge を導入した場合は // continue_target 側を優先する。 if let Some(target) = self.continue_target.or(self.loop_header) { self.jump_with_pred(target)?; } } } // 5. 現在ブロックは jump で終端済み。新しい unreachable ブロックは作らない。 Ok(void_id) } /// Handle a `break` statement: jump to loop exit and continue in a fresh unreachable block. /// 【箱化】do_loop_exit() への thin wrapper pub(super) fn do_break(&mut self) -> Result { self.do_loop_exit(LoopExitKind::Break) } /// Handle a `continue` statement: snapshot vars, jump to loop header, then continue in a fresh unreachable block. /// 【箱化】do_loop_exit() への thin wrapper pub(super) fn do_continue(&mut self) -> Result { self.do_loop_exit(LoopExitKind::Continue) } }