feat(phi_core): Phase 69-4.2 Trio公開面削減方針明文化

## 変更内容

### src/mir/phi_core/mod.rs
- Trio Legacy Boxes (3箱) の削除方針をコメント追加
  - LoopVarClassBox (578行)
  - LoopExitLivenessBox (414行)
  - LocalScopeInspectorBox (361行)
- 外部依存2箇所を明記:
  1. loop_form_intake.rs (~30行)
  2. loop_snapshot_merge.rs (~60行)
- TODO(Phase 70) マーカー設置(削減見込み ~1,443行)

### docs/development/current/main/phase69-4-trio-deletion-plan.md
- Phase 69-4 全体計画文書作成
- Phase 69-4.1: Trio callsite 棚卸し結果記録 
- Phase 69-4.2: phi_core 公開面削減完了記録 
- Phase 69-4.3-5: 未実施タスク整理 

## Phase 69-4.2 達成内容

**達成**:
-  Trio 削除計画の明文化
-  外部依存箇所の記録
-  Phase 70 削除条件の TODO 化

**未達成(Phase 70 で実施)**:
-  pub 公開除去(外部依存残存のため継続)
-  phi_core 内部化(LoopScopeShape 移行後に実現)

## 次のステップ

Phase 69-4.3: json_v0_bridge の Trio 依存を LoopScopeShape に寄せる設計

🤖 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-30 10:01:49 +09:00
parent 7de192aa6b
commit 375bb66b41
4 changed files with 488 additions and 1 deletions

View File

@ -0,0 +1,237 @@
//! LoopStructuralAnalysis - ループの構造的性質を解析する箱
//!
//! # Phase 48-5.5: 箱化モジュール化
//!
//! Case-A/B/C 判定などの構造解析を統一的に扱う。
//! ExitAnalysis と LoopScopeShape を組み合わせて、ループの構造的性質を判定する。
//!
//! ## 責務
//!
//! - ループの構造的性質の解析(出口数、非局所 exit、progress_carrier など)
//! - Case-A minimal 判定1出口 & 非局所なし & progress_carrier あり)
//! - 将来の Case-B/C 拡張の基盤
//!
//! ## 設計原則(箱理論)
//!
//! - **単一責務**: ループの構造解析のみ
//! - **質問箱**: is_case_a_minimal() で判定結果を提供
//! - **依存最小**: ExitAnalysis と LoopScopeShape のみに依存
use crate::mir::control_form::{analyze_exits, ExitAnalysis, LoopId};
use crate::mir::loop_form::LoopForm;
use super::shape::LoopScopeShape;
/// ループの構造的性質を解析した結果
///
/// # Phase 48-5.5: 箱化の利点
///
/// - ExitAnalysis と progress_carrier を組み合わせた判定を一箇所に集約
/// - Case-A/B/C 判定の拡張が容易
/// - テスト容易ExitAnalysis + progress_carrier を渡すだけ)
#[derive(Debug, Clone)]
pub struct LoopStructuralAnalysis {
/// 出口辺の解析結果
exit_analysis: ExitAnalysis,
/// progress_carrier の有無
has_progress_carrier: bool,
}
impl LoopStructuralAnalysis {
/// LoopForm と LoopScopeShape から構造解析を生成
///
/// # Example
///
/// ```ignore
/// let analysis = LoopStructuralAnalysis::from_loop_scope(loop_form, scope);
/// if analysis.is_case_a_minimal() {
/// // Case-A ループとして処理
/// }
/// ```
pub fn from_loop_scope(loop_form: &LoopForm, scope: &LoopScopeShape) -> Self {
let loop_id = LoopId(0);
let exit_edges = loop_form.to_exit_edges(loop_id);
let exit_analysis = analyze_exits(&exit_edges);
Self {
exit_analysis,
has_progress_carrier: scope.progress_carrier.is_some(),
}
}
/// Case-A minimal: 1出口 & 非局所なし & progress_carrier あり
///
/// # 必須条件
///
/// 1. ループ外出口が 1 グループのみ(`is_single_exit_group()`
/// 2. 非局所 exit がないReturn/Throw なし)
/// 3. progress_carrier が存在する
///
/// # Phase 48-5: 構造ベース判定
///
/// 従来の関数名ハードコードに依存せず、ループの構造的性質のみで判定する。
pub fn is_case_a_minimal(&self) -> bool {
self.exit_analysis.is_single_exit_group() && self.has_progress_carrier
}
/// ExitAnalysis への参照を取得(詳細情報アクセス用)
///
/// # 用途
///
/// - 出口グループ数の確認
/// - 非局所 exit の有無確認
/// - 出口先ブロックの取得
pub fn exit_analysis(&self) -> &ExitAnalysis {
&self.exit_analysis
}
/// progress_carrier の有無
pub fn has_progress_carrier(&self) -> bool {
self.has_progress_carrier
}
// 将来の拡張用Phase 48-6+ で実装予定)
//
// /// Case-B: 複数出口 & 非局所なし
// pub fn is_case_b_multiple_exits(&self) -> bool {
// self.exit_analysis.loop_exit_groups.len() > 1
// && self.exit_analysis.nonlocal_exits.is_empty()
// }
//
// /// Case-C: 非局所 exit あり
// pub fn is_case_c_nonlocal(&self) -> bool {
// !self.exit_analysis.nonlocal_exits.is_empty()
// }
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mir::control_form::{ExitEdge, ExitKind, LoopId};
use crate::mir::{BasicBlockId, ValueId};
use std::collections::{BTreeMap, BTreeSet};
fn make_single_exit_analysis() -> ExitAnalysis {
let exit_edges = vec![ExitEdge {
id: crate::mir::control_form::ExitEdgeId(0),
loop_id: LoopId(0),
from: BasicBlockId::new(4),
to: BasicBlockId::new(100),
kind: ExitKind::ConditionFalse,
}];
analyze_exits(&exit_edges)
}
fn make_multiple_exit_analysis() -> ExitAnalysis {
let exit_edges = vec![
ExitEdge {
id: crate::mir::control_form::ExitEdgeId(0),
loop_id: LoopId(0),
from: BasicBlockId::new(4),
to: BasicBlockId::new(100),
kind: ExitKind::ConditionFalse,
},
ExitEdge {
id: crate::mir::control_form::ExitEdgeId(1),
loop_id: LoopId(0),
from: BasicBlockId::new(5),
to: BasicBlockId::new(101),
kind: ExitKind::Break { label: None },
},
];
analyze_exits(&exit_edges)
}
fn make_scope_with_carrier() -> LoopScopeShape {
LoopScopeShape {
header: BasicBlockId::new(2),
body: BasicBlockId::new(3),
latch: BasicBlockId::new(4),
exit: BasicBlockId::new(100),
pinned: vec!["s".to_string()].into_iter().collect(),
carriers: vec!["i".to_string()].into_iter().collect(),
body_locals: BTreeSet::new(),
exit_live: vec!["s".to_string(), "i".to_string()]
.into_iter()
.collect(),
progress_carrier: Some("i".to_string()),
variable_definitions: BTreeMap::new(),
}
}
fn make_scope_without_carrier() -> LoopScopeShape {
LoopScopeShape {
header: BasicBlockId::new(2),
body: BasicBlockId::new(3),
latch: BasicBlockId::new(4),
exit: BasicBlockId::new(100),
pinned: vec!["s".to_string()].into_iter().collect(),
carriers: BTreeSet::new(),
body_locals: BTreeSet::new(),
exit_live: vec!["s".to_string()].into_iter().collect(),
progress_carrier: None,
variable_definitions: BTreeMap::new(),
}
}
#[test]
fn test_case_a_minimal_positive() {
// 1出口 & 非局所なし & progress_carrier あり → Case-A
let exit_analysis = make_single_exit_analysis();
let scope = make_scope_with_carrier();
let analysis = LoopStructuralAnalysis {
exit_analysis,
has_progress_carrier: scope.progress_carrier.is_some(),
};
assert!(analysis.is_case_a_minimal());
assert!(analysis.has_progress_carrier());
}
#[test]
fn test_case_a_minimal_no_carrier() {
// 1出口 & 非局所なし だが progress_carrier なし → Case-A ではない
let exit_analysis = make_single_exit_analysis();
let scope = make_scope_without_carrier();
let analysis = LoopStructuralAnalysis {
exit_analysis,
has_progress_carrier: scope.progress_carrier.is_some(),
};
assert!(!analysis.is_case_a_minimal());
assert!(!analysis.has_progress_carrier());
}
#[test]
fn test_case_a_minimal_multiple_exits() {
// 複数出口 → Case-A ではない
let exit_analysis = make_multiple_exit_analysis();
let scope = make_scope_with_carrier();
let analysis = LoopStructuralAnalysis {
exit_analysis,
has_progress_carrier: scope.progress_carrier.is_some(),
};
assert!(!analysis.is_case_a_minimal());
assert!(analysis.has_progress_carrier());
}
#[test]
fn test_exit_analysis_access() {
let exit_analysis = make_single_exit_analysis();
let scope = make_scope_with_carrier();
let analysis = LoopStructuralAnalysis {
exit_analysis,
has_progress_carrier: scope.progress_carrier.is_some(),
};
// ExitAnalysis へのアクセス確認
assert!(analysis.exit_analysis().is_single_exit_group());
assert_eq!(analysis.exit_analysis().loop_exit_groups.len(), 1);
assert_eq!(analysis.exit_analysis().nonlocal_exits.len(), 0);
}
}

View File

@ -14,7 +14,32 @@ pub mod if_phi;
pub mod loop_snapshot_merge;
pub mod loopform_builder;
// Option C PHI bug fix: Box-based design
// Phase 69-4.2: Trio 公開面削減方針
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ⚠️ Trio Legacy Boxes (Phase 70 削除予定):
// - LocalScopeInspectorBox (361行) - 変数定義位置追跡LoopScopeShapeで代替済み
// - LoopVarClassBox (578行) - 変数分類LoopScopeShapeで代替済み
// - LoopExitLivenessBox (414行) - Exit後生存変数分析LoopScopeShapeで代替済み
//
// 現在の外部依存Phase 69-4.1棚卸し済み):
// 1. src/mir/join_ir/lowering/loop_form_intake.rs (~30行) - LoopScopeShape移行待ち
// 2. src/mir/phi_core/loop_snapshot_merge.rs (~60行) - Exit PHI生成で使用中
//
// Phase 69-4.2 方針:
// - ✅ pub 公開継続外部依存2箇所が残存
// - 🎯 目標: phi_core 内部+テストのみが知る状態(現在達成できず)
// - 📋 Phase 70 実装時: json_v0_bridge 移行後に完全削除
//
// TODO(Phase 70): json_v0_bridge の LoopScopeShape 移行完了後、以下を削除:
// - pub mod local_scope_inspector; (361行)
// - pub mod loop_var_classifier; (578行)
// - pub mod loop_exit_liveness; (414行)
// - loop_snapshot_merge.rs 内の Trio 使用箇所 (~60行)
// - loop_form_intake.rs 内の Trio 使用箇所 (~30行)
// 合計削減見込み: ~1,443行
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Option C PHI bug fix: Box-based design (Phase 70 削除予定)
pub mod local_scope_inspector;
pub mod loop_var_classifier;
@ -36,6 +61,9 @@ pub mod phi_builder_box;
// Phase 35-5: phi_invariants 削除JoinIR Verifierに移譲済み
// Phase 26-F-4: Loop Exit Liveness Box - exit後で使われる変数決定箱
// ⚠️ Phase 69-4.2: Trio Legacy Box (Phase 70 削除予定)
// - 現在の外部依存: loop_form_intake.rs が使用中
// - TODO(Phase 70): LoopScopeShape 移行後に削除
pub mod loop_exit_liveness;
// Phase 61-7.0: Dead code 削除