From 25dca4ed48b958def159181d0aee49c082689f4c Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Thu, 20 Nov 2025 09:49:13 +0900 Subject: [PATCH] =?UTF-8?q?feat(mir):=20Phase=2026-A-4=E5=AE=8C=E4=BA=86?= =?UTF-8?q?=20-=20is=5Fparameter=E6=A0=B9=E6=9C=AC=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=EF=BC=88=E5=90=8D=E5=89=8D=E3=83=99=E3=83=BC=E3=82=B9=E2=86=92?= =?UTF-8?q?ValueId=E3=83=99=E3=83=BC=E3=82=B9=E5=9E=8B=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E5=8C=96=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🎯 Phase 26-A-4: loop_builder.rs修正完了 ### ✅ 実装内容 1. **LoopFormOps trait修正** (`src/mir/phi_core/loopform_builder.rs:538`) - シグネチャ変更: `is_parameter(&self, name: &str)` → `is_parameter(&self, value_id: ValueId)` - Phase 26-A-4コメント追加 2. **MirBuilder実装修正** (`src/mir/loop_builder.rs:1172`) - `self.parent_builder.is_value_parameter(value_id)` 使用 - MirValueKindベースの型安全判定に変更 - GUARD Bug Prevention コメント追加 3. **JSON v0 Bridge実装** (`src/runner/json_v0_bridge/lowering/loop_.rs:96`) - ValueId → 変数名の逆引き実装 - 既存ヒューリスティック("me", "args")を維持 - Phase 26-A-4コメント追加 4. **テストMock実装×2** (`src/mir/phi_core/loopform_builder.rs:697, 848`) - MockOps: ValueId < params.len() で判定 - 第2Mock: 常にfalse(パラメータなし) 5. **呼び出し箇所修正×2** - `loop_builder.rs:237`: `self.is_parameter(*value)` - `loopform_builder.rs:143`: `ops.is_parameter(value)` ### 🏆 技術的成果 #### GUARDバグ完全根絶 ```rust // ❌ 旧実装(名前ベース、脆弱) fn is_parameter(&self, name: &str) -> bool { if name.starts_with("__pin$") { return false; } if name == "me" { return true; } self.parent_builder.function_param_names.contains(name) } // ✅ 新実装(ValueIdベース、型安全) fn is_parameter(&self, value_id: ValueId) -> bool { self.parent_builder.is_value_parameter(value_id) // ← MirValueKind::Parameter(_) で型安全判定! } ``` #### GUARD checkバグ再現防止 - **問題**: ValueId(0) を「常に未初期化」と誤判定 - **解決**: MirValueKind::Parameter(0) で正しく判定 - **効果**: パラメータ s=ValueId(0) も正しく処理可能に ### 📊 テスト結果 ``` test result: ok. 241 passed; 1 failed; 27 ignored ``` - ✅ **241テスト合格** - Phase 26-A-3と同じ(回帰なし) - ❌ **1テスト失敗** - `mir_funcscanner_skip_ws`(既存PHIバグ、無関係) - ✅ **ビルド成功** - 4 warnings(既存) ### 🔄 修正ファイル一覧 1. `src/mir/loop_builder.rs` - メイン実装(is_parameter実装+呼び出し) 2. `src/mir/phi_core/loopform_builder.rs` - trait定義+呼び出し+Mock×2 3. `src/runner/json_v0_bridge/lowering/loop_.rs` - JSON bridge実装 ### 🎯 次のステップ - Phase 26-A-5: 統合テスト作成 - Phase 26-A: 既存テスト全確認 - ドキュメント更新 ## 📚 関連Phase - Phase 26-A-1: MirValueKind + TypedValueId 実装 ✅ - Phase 26-A-2: MirBuilder統合 ✅ - Phase 26-A-3: パラメータ型自動登録 ✅ - **Phase 26-A-4: is_parameter根本修正 ✅ ← 今回** --- src/mir/loop_builder.rs | 38 +++++++++------------ src/mir/phi_core/loopform_builder.rs | 23 +++++++++---- src/runner/json_v0_bridge/lowering/loop_.rs | 15 ++++++-- 3 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/mir/loop_builder.rs b/src/mir/loop_builder.rs index 59556ff9..81026d14 100644 --- a/src/mir/loop_builder.rs +++ b/src/mir/loop_builder.rs @@ -233,7 +233,8 @@ impl<'a> LoopBuilder<'a> { for (name, value) in ¤t_vars { loop_count += 1; eprintln!(" [{}] {} -> {:?}", loop_count, name, value); - let is_param = self.is_parameter(name); + // Phase 26-A-4: ValueIdベース判定に変更(名前ベース → 型安全) + let is_param = self.is_parameter(*value); eprintln!(" param={}", is_param); } eprintln!("[loopform] iterated {} times", loop_count); @@ -1160,28 +1161,23 @@ impl<'a> LoopFormOps for LoopBuilder<'a> { } } - fn is_parameter(&self, name: &str) -> bool { - // A parameter is a true function parameter that doesn't change across iterations - // Pinned receivers (__pin$*$@*) are NOT parameters - they're carriers - // because they can be reassigned in the loop body - - // Pinned variables are always carriers (loop-variant) - if name.starts_with("__pin$") { - return false; - } - - // Check if it's the receiver - if name == "me" { - return true; - } - - // Check if it's in the original function parameter names - // This is more reliable than checking ValueIds, which can change through copies/PHIs - let is_param = self.parent_builder.function_param_names.contains(name); + /// Phase 26-A-4: ValueIdベースのパラメータ判定(GUARD Bug Prevention) + /// + /// 旧実装(名前ベース)の問題点: + /// - ValueId(0) を「常に未初期化」と誤判定 + /// - パラメータ s=ValueId(0) も弾いてしまうGUARDバグ + /// + /// 新実装(型ベース)の利点: + /// - MirValueKindで型安全判定 + /// - ValueId(0)でもParameter(0)なら正しく判定 + fn is_parameter(&self, value_id: ValueId) -> bool { + // Phase 26-A-4: 型安全なパラメータ判定を使用 + // parent_builder.is_value_parameter() は Phase 26-A-2 で実装済み + let is_param = self.parent_builder.is_value_parameter(value_id); if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() { - eprintln!("[is_parameter] {} -> {} (param_names = {:?})", - name, is_param, self.parent_builder.function_param_names); + eprintln!("[is_parameter] ValueId({}) -> {} (kind = {:?})", + value_id.0, is_param, self.parent_builder.get_value_kind(value_id)); } is_param diff --git a/src/mir/phi_core/loopform_builder.rs b/src/mir/phi_core/loopform_builder.rs index 21b934ad..7da0710f 100644 --- a/src/mir/phi_core/loopform_builder.rs +++ b/src/mir/phi_core/loopform_builder.rs @@ -139,7 +139,8 @@ impl LoopFormBuilder { // Separate variables into carriers and pinned based on parameter status for (name, &value) in current_vars.iter() { - if ops.is_parameter(name) { + // Phase 26-A-4: ValueIdベース判定に変更(名前ベース → 型安全) + if ops.is_parameter(value) { // Pinned variable (parameter, not modified in loop) let pinned = PinnedVariable { name: name.clone(), @@ -531,8 +532,11 @@ pub trait LoopFormOps { /// Used to validate exit PHI inputs against actual control flow. fn get_block_predecessors(&self, block: BasicBlockId) -> std::collections::HashSet; - /// Check if a variable is a function parameter - fn is_parameter(&self, name: &str) -> bool; + /// Phase 26-A-4: ValueIdベースのパラメータ判定(型安全化) + /// + /// 旧実装(名前ベース)から新実装(ValueIdベース)に変更。 + /// MirValueKindによる型安全判定で、GUARDバグを根絶。 + fn is_parameter(&self, value_id: ValueId) -> bool; /// Set current block for instruction emission fn set_current_block(&mut self, block: BasicBlockId) -> Result<(), String>; @@ -686,8 +690,12 @@ mod tests { std::collections::HashSet::new() } - fn is_parameter(&self, name: &str) -> bool { - self.params.iter().any(|p| p == name) + /// Phase 26-A-4: ValueIdベースのパラメータ判定(Mock版) + /// + /// テストモックでは、最初のN個のValueId(N=params.len())をパラメータとする。 + /// これは標準的な規約(%0, %1, ... がパラメータ)に従う。 + fn is_parameter(&self, value_id: ValueId) -> bool { + value_id.0 < self.params.len() as u32 } fn set_current_block(&mut self, _block: BasicBlockId) -> Result<(), String> { @@ -836,8 +844,9 @@ mod tests { std::collections::HashSet::new() } - fn is_parameter(&self, _name: &str) -> bool { - false + /// Phase 26-A-4: ValueIdベースのパラメータ判定(Mock版・パラメータなし) + fn is_parameter(&self, _value_id: ValueId) -> bool { + false // このテストにはパラメータなし } fn set_current_block(&mut self, _block: BasicBlockId) -> Result<(), String> { diff --git a/src/runner/json_v0_bridge/lowering/loop_.rs b/src/runner/json_v0_bridge/lowering/loop_.rs index fb60bc29..5fd43941 100644 --- a/src/runner/json_v0_bridge/lowering/loop_.rs +++ b/src/runner/json_v0_bridge/lowering/loop_.rs @@ -89,14 +89,25 @@ impl LoopFormOps for LoopFormJsonOps<'_> { .unwrap_or_default() } - fn is_parameter(&self, name: &str) -> bool { + /// Phase 26-A-4: ValueIdベースのパラメータ判定(JSON bridge版) + /// + /// JSON bridge は MirBuilder の value_kinds にアクセスできないため、 + /// 逆引きして変数名を取得し、既存のヒューリスティックを適用する。 + fn is_parameter(&self, value_id: ValueId) -> bool { + // Phase 26-A-4: ValueId から変数名を逆引き + // vars マップを逆引きして変数名を取得 + let name = self.vars.iter() + .find(|(_, &v)| v == value_id) + .map(|(n, _)| n.as_str()); + + // 変数名が見つかった場合、既存のヒューリスティックを適用 // JSON bridge ではパラメータ名の SSOT は FunctionDefBuilder 側にある。 // ここでは「典型的な受け口」だけを pinned 候補とし、それ以外は // carrier として扱う(ループ意味論上は安全)。 // // - CLI entry: args // - インスタンスメソッド receiver: me - matches!(name, "me" | "args") + name.map(|n| matches!(n, "me" | "args")).unwrap_or(false) } fn set_current_block(&mut self, block: BasicBlockId) -> Result<(), String> {