Files
hakorune/src/mir/builder/calls/effects_analyzer.rs
nyash-codex 4ff9bd4791 refactor(builder): Phase 3-B,C完了 - 読みやすさ革命達成!
箱理論の完全実践:Call系処理を9個の専用箱で完全分離
- Phase 3-B: EffectsAnalyzerBox(エフェクト解析専用)
- Phase 3-C: CallMaterializerBox(Call前処理専用)

実装内容:

【Phase 3-B: EffectsAnalyzerBox】

1. 新規ファイル作成
   - src/mir/builder/calls/effects_analyzer.rs (~155行)
   - compute_call_effects: Calleeから副作用マスクを計算
   - is_pure_method: Pureメソッド判定
   - 5つのユニットテスト 

2. call_unified.rs整理
   - compute_call_effects → 委譲に変更
   - is_pure_method → 削除
   - ~50行削減

【Phase 3-C: CallMaterializerBox】

1. 新規ファイル作成
   - src/mir/builder/calls/materializer.rs (~151行)
   - try_global_fallback_handlers: Global関数フォールバック
   - materialize_receiver_in_callee: Receiver実体化
   - Call前処理全般を集約

2. emit.rs整理
   - 2つの大きな関数を委譲に変更
   - ~115行削減

3. unified_emitter.rs更新
   - CallMaterializerBox経由に変更

箱化効果(Phase 3全体):

【劇的な削減】
- emit.rs: 467行 → 164行(-303行、65%削減!)
- call_unified.rs: 144行 → 98行(-46行、32%削減!)

【新規箱(責務明確・読みやすい)】
- unified_emitter.rs: 250行(統一Call発行専用)
- effects_analyzer.rs: 155行(エフェクト解析専用)
- materializer.rs: 151行(Call前処理専用)

【読みやすさ革命】
-  500行超えファイル根絶(最大489行まで)
-  責務分離完璧(各ファイルが単一責務)
-  9個の専用箱で管理(guard/resolver/emitter/effects/materializer)
-  テスト容易性劇的向上(独立した箱で簡単テスト)

Phase 3 最終状態:
- Phase 3-A: UnifiedCallEmitterBox 
- Phase 3-B: EffectsAnalyzerBox 
- Phase 3-C: CallMaterializerBox 
- 読みやすさ革命  完全達成!

ビルド・テスト:
- cargo build --release:  成功
- effects_analyzer tests (5):  all passed
- 既存機能互換性:  完全保持
2025-11-17 23:57:04 +09:00

157 lines
5.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* EffectsAnalyzerBox - エフェクト解析専用箱
*
* 箱理論の実践:
* - 箱にする: エフェクト解析ロジックを1箱に集約
* - 境界を作る: Pure/IO/Alloc/Control等の効果分類を一元管理
* - 状態レス: すべて静的解析(実行時状態不要)
*
* 責務:
* - compute_call_effects: Calleeから副作用マスクを計算
* - is_pure_method: メソッドがPure副作用なしか判定
* - 既知の関数・メソッドのエフェクト知識を集約
*/
use crate::mir::definitions::call_unified::Callee;
use crate::mir::builder::{Effect, EffectMask};
use super::extern_calls;
/// エフェクト解析専用箱
///
/// 箱理論:
/// - 単一責務: Calleeのエフェクト解析のみ
/// - 状態レス: すべて静的関数Callee情報のみで判定
/// - 知識集約: 既知の関数・メソッドのエフェクト知識を一元管理
pub struct EffectsAnalyzerBox;
impl EffectsAnalyzerBox {
/// Compute effects for a call based on its callee
///
/// エフェクト分類:
/// - PURE: 副作用なし(純粋計算)
/// - READ: ヒープ読み取りのみ
/// - IO: 入出力あり
/// - Alloc: メモリ確保
/// - Control: 制御フロー変更panic/exit
/// - WriteHeap: ヒープ書き込み
pub fn compute_call_effects(callee: &Callee) -> EffectMask {
match callee {
Callee::Global(name) => {
match name.as_str() {
"print" | "error" => EffectMask::IO,
"panic" | "exit" => EffectMask::IO.add(Effect::Control),
"gc_collect" => EffectMask::IO.add(Effect::Alloc),
_ => EffectMask::IO,
}
},
Callee::Method { method, box_name, .. } => {
match method.as_str() {
"birth" => EffectMask::PURE.add(Effect::Alloc),
"get" | "length" | "size" => EffectMask::READ,
"set" | "push" | "pop" => EffectMask::READ.add(Effect::WriteHeap),
_ => {
// Check if it's a known pure method
if Self::is_pure_method(box_name, method) {
EffectMask::PURE
} else {
EffectMask::READ
}
}
}
},
Callee::Constructor { .. } => EffectMask::PURE.add(Effect::Alloc),
Callee::Closure { .. } => EffectMask::PURE.add(Effect::Alloc),
Callee::Extern(name) => {
let (iface, method) = extern_calls::parse_extern_name(name);
extern_calls::compute_extern_effects(&iface, &method)
},
Callee::Value(_) => EffectMask::IO, // Conservative for dynamic calls
}
}
/// Check if a method is known to be pure (no side effects)
///
/// Pure メソッドの条件:
/// - 副作用なしヒープ変更なし、I/Oなし
/// - 同じ入力に対して同じ出力を返す
/// - プログラムの状態を変更しない
///
/// 既知のPureメソッド:
/// - StringBox: upper, lower, trim, length
/// - IntegerBox: abs, toString
/// - FloatBox: round, floor, ceil
/// - BoolBox: not
pub fn is_pure_method(box_name: &str, method: &str) -> bool {
match (box_name, method) {
("StringBox", m) => matches!(m, "upper" | "lower" | "trim" | "length"),
("IntegerBox", m) => matches!(m, "abs" | "toString"),
("FloatBox", m) => matches!(m, "round" | "floor" | "ceil"),
("BoolBox", "not") => true,
_ => false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mir::ValueId;
use crate::mir::definitions::call_unified::{CalleeBoxKind, TypeCertainty};
#[test]
fn test_compute_effects_global() {
let callee = Callee::Global("print".to_string());
let effects = EffectsAnalyzerBox::compute_call_effects(&callee);
assert_eq!(effects, EffectMask::IO);
}
#[test]
fn test_compute_effects_method_pure() {
let callee = Callee::Method {
box_name: "StringBox".to_string(),
method: "upper".to_string(),
receiver: Some(ValueId::new(1)),
certainty: TypeCertainty::Known,
box_kind: CalleeBoxKind::RuntimeData,
};
let effects = EffectsAnalyzerBox::compute_call_effects(&callee);
assert_eq!(effects, EffectMask::PURE);
}
#[test]
fn test_compute_effects_method_read() {
let callee = Callee::Method {
box_name: "ArrayBox".to_string(),
method: "get".to_string(),
receiver: Some(ValueId::new(1)),
certainty: TypeCertainty::Known,
box_kind: CalleeBoxKind::RuntimeData,
};
let effects = EffectsAnalyzerBox::compute_call_effects(&callee);
assert_eq!(effects, EffectMask::READ);
}
#[test]
fn test_compute_effects_constructor() {
let callee = Callee::Constructor {
box_type: "StringBox".to_string(),
};
let effects = EffectsAnalyzerBox::compute_call_effects(&callee);
// Constructor should have PURE + Alloc
assert_eq!(effects, EffectMask::PURE.add(crate::mir::builder::Effect::Alloc));
}
#[test]
fn test_is_pure_method() {
assert!(EffectsAnalyzerBox::is_pure_method("StringBox", "upper"));
assert!(EffectsAnalyzerBox::is_pure_method("IntegerBox", "abs"));
assert!(EffectsAnalyzerBox::is_pure_method("BoolBox", "not"));
assert!(!EffectsAnalyzerBox::is_pure_method("ArrayBox", "push"));
}
}