refactor(mir): Phase 25.1o - do_break/continue 共通化(LoopExitKind型統一)

【変更内容】
1. LoopExitKind enum定義
   - Break / Continue の型安全な区別

2. do_loop_exit() 共通メソッド作成(47行)
   - スナップショット取得(共通処理)
   - kind別のスナップショット保存
   - kind別のジャンプターゲット
   - unreachable ブロック切り替え(共通処理)

3. do_break/continue をthin wrapperに変換
   - do_break: 13行 → 4行
   - do_continue: 12行 → 4行
   - 合計21行削減

【効果】
- 構造改善: break/continue の共通ロジック一箇所に集約
- 保守性向上: デバッグログなどの共通処理が統一管理
- 拡張性向上: labeled break/continue等の将来拡張が容易

【検証結果】
- ビルド成功(警告なし)
- mir_stageb_loop_break_continue_verifies: PASS
- /tmp/loop_continue_fixed.hako: RC=3(期待通り)

関連: Phase 25.1m (continue PHI修正), Phase 25.1n (レガシー削除)
This commit is contained in:
nyash-codex
2025-11-19 08:56:44 +09:00
parent 77fc670cd3
commit 75f3df2505
11 changed files with 92 additions and 89 deletions

View File

@ -17,6 +17,15 @@ use super::utils::{
capture_actual_predecessor_and_jump,
};
/// ループ脱出の種類(箱化・共通化のための型)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum LoopExitKind {
/// break文exit blockへジャンプ
Break,
/// continue文header blockへジャンプ
Continue,
}
/// ループビルダー - SSA形式でのループ構築を管理
pub struct LoopBuilder<'a> {
/// 親のMIRビルダーへの参照
@ -67,34 +76,64 @@ impl<'a> LoopBuilder<'a> {
Ok(void_id)
}
/// Handle a `break` statement: jump to loop exit and continue in a fresh unreachable block.
fn do_break(&mut self) -> Result<ValueId, String> {
// Snapshot variables at break point for exit PHI generation
/// 【箱化】ループ脱出の共通処理break/continue統一化
///
/// Phase 25.1o: break と continue の共通パターンを抽出し、
/// LoopExitKind で振る舞いを切り替える統一メソッド。
///
/// # 処理フロー
/// 1. 現在の変数マップをスナップショット
/// 2. 適切なスナップショットリストに追加Break → exit_snapshots, Continue → continue_snapshots
/// 3. ターゲットブロックへジャンプBreak → exit, Continue → header
/// 4. unreachable ブロックに切り替え
fn do_loop_exit(&mut self, kind: LoopExitKind) -> Result<ValueId, String> {
// 1. スナップショット取得(共通処理)
let snapshot = self.get_current_variable_map();
let cur_block = self.current_block()?;
eprintln!("[DEBUG/do_break] Saved snapshot from block {:?}, vars: {:?}",
cur_block, snapshot.keys().collect::<Vec<_>>());
self.exit_snapshots.push((cur_block, snapshot));
if let Some(exit_bb) = crate::mir::builder::loops::current_exit(self.parent_builder) {
self.jump_with_pred(exit_bb)?;
// 2. スナップショット保存kind別処理
match kind {
LoopExitKind::Break => {
if std::env::var("NYASH_LOOPFORM_DEBUG").ok().as_deref() == Some("1") {
eprintln!("[DEBUG/do_break] Saved snapshot from block {:?}, vars: {:?}",
cur_block, snapshot.keys().collect::<Vec<_>>());
}
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. ターゲットブロックへジャンプ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 => {
if let Some(header) = self.loop_header {
self.jump_with_pred(header)?;
}
}
}
// 4. unreachable ブロックに切り替え(共通処理)
self.switch_to_unreachable_block_with_void()
}
/// Handle a `break` statement: jump to loop exit and continue in a fresh unreachable block.
/// 【箱化】do_loop_exit() への thin wrapper
fn do_break(&mut self) -> Result<ValueId, String> {
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
fn do_continue(&mut self) -> Result<ValueId, String> {
// Snapshot variables at current block to be considered as a predecessor input
let snapshot = self.get_current_variable_map();
let cur_block = self.current_block()?;
self.block_var_maps.insert(cur_block, snapshot.clone());
self.continue_snapshots.push((cur_block, snapshot));
if let Some(header) = self.loop_header {
self.jump_with_pred(header)?;
}
self.switch_to_unreachable_block_with_void()
self.do_loop_exit(LoopExitKind::Continue)
}
// =============================================================