refactor(mir): Phase 25.1n - レガシーコード削除(未使用コード整理)

**削減内容**:
- loop_builder.rs: incomplete_phis, emit_safepoint, mark_block_sealed (-28行)
- builder.rs: hint_loop_*, debug_loop_*, debug_replace_region (-28行)
- builder/loops.rs: create_loop_blocks (-9行)

**成果**:
- コード削減: 65行の未使用コード削除
- 警告削減: 7個 → 2個 (71%削減)
- 機能維持: すべてのテスト通過 

**削除されたレガシーAPI**:
- incomplete_phis フィールド (LoopFormBuilder移行後未使用)
- emit_safepoint() メソッド (未使用)
- mark_block_sealed() メソッド (未使用)
- hint_loop_header/latch/carrier() (ヒントシステム未使用)
- debug_next_loop_id() (デバッグ機能未使用)
- debug_replace_region() (デバッグ機能未使用)
- create_loop_blocks() (LoopForm v2移行後未使用)

🧹 箱化・モジュール化の第一歩として未使用コード整理完了

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-19 08:35:56 +09:00
parent a95fedf26a
commit 77fc670cd3
5 changed files with 234 additions and 1909 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
# Phase 25.1m — Static Method / VM Param Semantics Bugfix
Status: planningRust 側の暗黙レシーバ問題を切り出したバグ修正フェーズ
Status: completed静的メソッド / LoopForm v2 continue + PHI の根治完了
## ゴール
@ -12,7 +12,7 @@ Status: planningRust 側の暗黙レシーバ問題を切り出したバグ
- VM 内部: `params.len() == 1`、args 1 本 → `bar` の唯一の引数に `"HELLO"` が入る
- 「暗黙の receiver仮想 me」を静的メソッドにだけ特別扱いしない設計に戻す。
## 現状の症状2025-11-18 時点)
## 実際に起きていた症状2025-11-18 時点)
- 再現(簡易例):
```hako
@ -44,7 +44,7 @@ Status: planningRust 側の暗黙レシーバ問題を切り出したバグ
- 25.1d/e で扱っていた Stage1 UsingResolver 系テスト(`collect_entries/1`)でも、
`%0` / `%1` の扱いに由来する SSA 破綻が見えていた(現在は LoopForm v2/Conservative PHI 側で多くを解消済みだが、根底の呼び出し規約はまだ歪なまま)。
## スコープ25.1m でやこと)
## スコープ25.1m でやったこと)
1. 呼び出し規約の SSOT を決める
- 原則:
@ -66,18 +66,29 @@ Status: planningRust 側の暗黙レシーバ問題を切り出したバグ
- 次に `Stage1UsingResolverFull.collect_entries/1` を LoopForm v2 経路込みで通し、
`%0` / `%1` の ValueId 割り当てと PHI が健全であることを `MirVerifier` のテストで確認する。
3. 実装方針(高レベル)
- `MirFunction::new`:
- 暗黙 receiver 判定を段階縮小し、最終的には「インスタンスメソッドのみ `MirType::Box(_)` を用いた明示的 receiver」に統一
- 静的メソッド(`static box Foo { method bar(x){...} }`)は `signature.params == [Unknown]` のみを予約対象にし
追加の `receiver_count` を持たない設計に戻す
- `emit_unified_call`:
- Method call のみ receiver を args に足す (`args_local.insert(0, recv)`)、Global/static 呼び出しでは一切いじらない。
- `exec_function_inner`:
- 現状の「params[] と args[] を 1:1 でバインドする」実装を前提として保ち、
呼び出し規約の側MIR builder 側)で整合を取る。
3. 実装方針(高レベル・結果
- `MirFunction::new`(静的メソッド / 暗黙レシーバ):
- 暗黙 receiver 判定を是正し、**Box 型の第 1 パラメータを持つ関数だけ**を「インスタンスメソッド with receiver」と見なすようにした
- 非 Box 型(`String`, `Integer` など)で始まるパラメータ列を持つ関数は、暗黙の receiver なしの静的メソッド / Global 関数として扱い
`signature.params.len()` と予約 ValueId 数が 1:1 になるように整理した
- `build_static_main_box``Main.main(args)` の扱い):
- `src/mir/builder/decls.rs` にて、`Main.main(args)` を静的エントリとして MIR 化する経路を
`NYASH_BUILD_STATIC_MAIN_ENTRY=1` 時のみ有効にし、通常の VM 実行では wrapper `main()` を正規エントリとするように変更した。
- LoopForm v2 / header PHI sealing:
- `src/mir/phi_core/loopform_builder.rs::LoopFormBuilder::seal_phis` を拡張し、preheader + latch に加えて
**`continue_snapshots` からの入力も header PHI に統合**するようにした。
- これにより、balanced scan など「ループ本体で変数更新 → `continue` → 次イテレーション」のパターンでも、
header で参照される変数が preheader / continue / latch すべての predecessor から正しくマージされる。
- LoopBuilder から LoopForm への continue 橋渡し:
- `src/mir/loop_builder.rs::build_loop_with_loopform` から `self.continue_snapshots.clone()` を `seal_phis` に渡し、
LoopBuilder が集めた continue 時点のスナップショットを LoopForm メタボックス側の PHI 入力に反映するようにした。
- ControlForm / LoopShape invariants:
- `src/mir/control_form.rs::LoopShape::debug_validate` に以下の invariant を追加debug ビルドのみ):
- `continue_targets` の各ブロックから `header` へのエッジが存在すること。
- `break_targets` の各ブロックから `exit` へのエッジが存在すること。
- これにより、continue / break 経路の CFG 破綻があれば構造レベルで早期に検知できる。
## 非スコープ25.1m でやらないこと)
## 非スコープ25.1m では扱わなかったこと)
- 言語仕様の変更:
- Hako/Nyash の静的メソッド構文 (`static box` / `method`) 自体は変更しない。
@ -86,7 +97,7 @@ Status: planningRust 側の暗黙レシーバ問題を切り出したバグ
- VM 命令や Box 実装の追加:
- 25 フェーズのポリシーに従い、新しい命令・Box 機能は追加しない(既存の呼び出し規約を整えるだけ)。
## 関連フェーズとの関係
## 関連フェーズとの関係と結果
- Phase 25.1d/e/g/k/l:
- Rust MIR 側の SSA/PHI特に LoopForm v2 + Conservative PHIと Region 観測レイヤは、静的メソッドを含む多くのケースで安定している。
@ -96,13 +107,20 @@ Status: planningRust 側の暗黙レシーバ問題を切り出したバグ
- StageBTraceBox は既にインスタンス box 化しており、静的メソッドのバグを踏まないようにしてある。
- 25.1m で静的メソッド呼び出し規約が直れば、将来的に Trace 系 Box を static 化することも再検討できる。
## 受け入れ条件25.1m
## 受け入れ結果25.1m 実績
- 新規ユニットテスト:
- 簡易 TraceTest静的メソッド + 文字列引数)の MIR/VM 実行が `label=HELLO` となること
- `mir_stage1_using_resolver_full_collect_entries_verifies` が LoopForm v2 経路で緑のまま(または改善)であること
- 既存の StageB / selfhost / 数値系テスト:
- 25.1c までに整えた StageB / selfhost ラインの canaryfib defs / CLI runが、25.1m の変更で悪化していないこと
- 挙動の安定:
- 静的メソッド呼び出しに関する「引数が null になる」「ValueId %0 が未定義になる」といった VM エラーが、新規テスト群で再現しないこと。
- 静的メソッド / 暗黙レシーバ:
- StageB の `StageBTraceBox.log(label)` 呼び出しで、`"StageBArgsBox.resolve_src:enter"` 等のラベルが **null 化されずに正しく渡る** ことを確認
- `Main.main(args)` ループ未実行バグは、静的エントリ生成を env フラグ付きに限定し、wrapper `main()` を正規エントリとしたことで解消
- LoopForm v2 / continue + PHI:
- 開発用 Hako`loop_continue_fixed.hako`)で `RC=3` + PHI エラーなしを確認
- StageB balanced scan ループに 228 回のイテレーショントレースを付け、`ch == "{"` ブランチ後の `continue` で正常に次イテレーションへ戻ることを Rust VM 実行で確認。
- 新規ユニットテスト `test_seal_phis_includes_continue_snapshots` と、既存の
`mir_stageb_loop_break_continue_verifies` / `mir_stage1_using_resolver_full_collect_entries_verifies`
の両方が緑であることを `cargo test` ベースで確認。
## 25.1m 完了後に残っている課題(次フェーズ向けメモ)
- StageB 本体:
- `Main.main` 処理内で `String(...) > Integer(13)` のような異種型比較に起因する型エラーが残っているcontinue/PHI 修正とは独立)。
- これは StageB の JSON 生成 / body_src 構造に属する問題のため、25.1m では扱わず、25.1c 続き or 次フェーズで箱単位に切り出して対応する。

View File

@ -186,8 +186,7 @@ pub struct MirBuilder {
// ----------------------
/// Stack of region identifiers like "loop#1/header" or "join#3/join".
debug_scope_stack: Vec<String>,
/// Monotonic counters for region IDs (deterministic across a run).
debug_loop_counter: u32,
/// Monotonic counter for region IDs (deterministic across a run).
debug_join_counter: u32,
/// Local SSA cache: ensure per-block materialization for critical operands (e.g., recv)
@ -268,7 +267,6 @@ impl MirBuilder {
// Debug scope context
debug_scope_stack: Vec::new(),
debug_loop_counter: 0,
debug_join_counter: 0,
local_ssa_map: HashMap::new(),
@ -290,30 +288,15 @@ impl MirBuilder {
// ---- Hint helpers (no-op by default) ----
#[inline]
pub(crate) fn hint_loop_header(&mut self) { self.hint_sink.loop_header(); }
#[inline]
pub(crate) fn hint_loop_latch(&mut self) { self.hint_sink.loop_latch(); }
#[inline]
pub(crate) fn hint_scope_enter(&mut self, id: u32) { self.hint_sink.scope_enter(id); }
#[inline]
pub(crate) fn hint_scope_leave(&mut self, id: u32) { self.hint_sink.scope_leave(id); }
#[inline]
pub(crate) fn hint_join_result<S: Into<String>>(&mut self, var: S) { self.hint_sink.join_result(var.into()); }
#[inline]
pub(crate) fn hint_loop_carrier<S: Into<String>>(&mut self, vars: impl IntoIterator<Item = S>) {
self.hint_sink.loop_carrier(vars.into_iter().map(|s| s.into()).collect::<Vec<_>>());
}
// ----------------------
// Debug scope helpers (region_id for DebugHub events)
// ----------------------
#[inline]
pub(crate) fn debug_next_loop_id(&mut self) -> u32 {
let id = self.debug_loop_counter;
self.debug_loop_counter = self.debug_loop_counter.saturating_add(1);
id
}
#[inline]
pub(crate) fn debug_next_join_id(&mut self) -> u32 {
let id = self.debug_join_counter;
@ -331,15 +314,6 @@ impl MirBuilder {
let _ = self.debug_scope_stack.pop();
}
#[inline]
pub(crate) fn debug_replace_region<S: Into<String>>(&mut self, region: S) {
if let Some(top) = self.debug_scope_stack.last_mut() {
*top = region.into();
} else {
self.debug_scope_stack.push(region.into());
}
}
#[inline]
pub(crate) fn debug_current_region_id(&self) -> Option<String> {
self.debug_scope_stack.last().cloned()

View File

@ -1,15 +1,6 @@
//! Small loop utilities for MirBuilder
use super::{BasicBlockId, MirBuilder};
/// Create header/body/after blocks for a loop and push loop context.
pub(crate) fn create_loop_blocks(builder: &mut MirBuilder) -> (BasicBlockId, BasicBlockId, BasicBlockId) {
let header = builder.block_gen.next();
let body = builder.block_gen.next();
let after = builder.block_gen.next();
push_loop_context(builder, header, after);
(header, body, after)
}
/// Push loop context (header/exit) onto the MirBuilder stacks.
pub(crate) fn push_loop_context(
builder: &mut super::MirBuilder,

View File

@ -7,7 +7,6 @@
use super::{BasicBlockId, ConstValue, MirInstruction, ValueId};
use crate::mir::control_form::{ControlForm, IfShape, LoopShape, is_control_form_trace_on};
use crate::mir::phi_core::loop_phi::IncompletePhi;
use crate::mir::phi_core::loopform_builder::{LoopFormBuilder, LoopFormOps};
use crate::ast::ASTNode;
use std::collections::HashMap;
@ -18,16 +17,11 @@ use super::utils::{
capture_actual_predecessor_and_jump,
};
// IncompletePhi has moved to phi_core::loop_phi
/// ループビルダー - SSA形式でのループ構築を管理
pub struct LoopBuilder<'a> {
/// 親のMIRビルダーへの参照
parent_builder: &'a mut super::builder::MirBuilder,
/// ループ内で追跡する変数の不完全Phi node
incomplete_phis: HashMap<BasicBlockId, Vec<IncompletePhi>>,
/// ブロックごとの変数マップ(スコープ管理)
#[allow(dead_code)]
block_var_maps: HashMap<BasicBlockId, HashMap<String, ValueId>>,
@ -108,15 +102,12 @@ impl<'a> LoopBuilder<'a> {
// =============================================================
/// 新しいループビルダーを作成
pub fn new(parent: &'a mut super::builder::MirBuilder) -> Self {
// フェーズM: no_phi_mode初期化削除
Self {
parent_builder: parent,
incomplete_phis: HashMap::new(),
block_var_maps: HashMap::new(),
loop_header: None,
continue_snapshots: Vec::new(),
exit_snapshots: Vec::new(), // exit PHI用のスナップショット
// フェーズM: no_phi_modeフィールド削除
}
}
@ -441,11 +432,6 @@ impl<'a> LoopBuilder<'a> {
})
}
fn emit_safepoint(&mut self) -> Result<(), String> {
self.parent_builder
.emit_instruction(MirInstruction::Safepoint)
}
fn emit_const(&mut self, dst: ValueId, value: ConstValue) -> Result<(), String> {
self.parent_builder
.emit_instruction(MirInstruction::Const { dst, value })
@ -551,20 +537,6 @@ impl<'a> LoopBuilder<'a> {
}
}
fn mark_block_sealed(&mut self, block_id: BasicBlockId) -> Result<(), String> {
if let Some(ref mut function) = self.parent_builder.current_function {
if let Some(block) = function.get_block_mut(block_id) {
block.seal();
Ok(())
} else {
Err(format!("Block {} not found", block_id))
}
} else {
Err("No current function".to_string())
}
}
// =============================================================
// Variable Map Utilities — snapshots and rebinding
// =============================================================