Files
hakorune/src/mir/builder/calls/effects_analyzer.rs
nyash-codex f9d100ce01 chore: Phase 25.1 完了 - LoopForm v2/Stage1 CLI/環境変数削減 + Phase 26-D からの変更
Phase 25.1 完了成果:
-  LoopForm v2 テスト・ドキュメント・コメント完備
  - 4ケース(A/B/C/D)完全テストカバレッジ
  - 最小再現ケース作成(SSAバグ調査用)
  - SSOT文書作成(loopform_ssot.md)
  - 全ソースに [LoopForm] コメントタグ追加

-  Stage-1 CLI デバッグ環境構築
  - stage1_cli.hako 実装
  - stage1_bridge.rs ブリッジ実装
  - デバッグツール作成(stage1_debug.sh/stage1_minimal.sh)
  - アーキテクチャ改善提案文書

-  環境変数削減計画策定
  - 25変数の完全調査・分類
  - 6段階削減ロードマップ(25→5、80%削減)
  - 即時削除可能変数特定(NYASH_CONFIG/NYASH_DEBUG)

Phase 26-D からの累積変更:
- PHI実装改善(ExitPhiBuilder/HeaderPhiBuilder等)
- MIRビルダーリファクタリング
- 型伝播・最適化パス改善
- その他約300ファイルの累積変更

🎯 技術的成果:
- SSAバグ根本原因特定(条件分岐内loop変数変更)
- Region+next_iパターン適用完了(UsingCollectorBox等)
- LoopFormパターン文書化・テスト化完了
- セルフホスティング基盤強化

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: ChatGPT <noreply@openai.com>
Co-Authored-By: Task Assistant <task@anthropic.com>
2025-11-21 06:25:17 +09:00

160 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 super::extern_calls;
use crate::mir::builder::{Effect, EffectMask};
use crate::mir::definitions::call_unified::Callee;
/// エフェクト解析専用箱
///
/// 箱理論:
/// - 単一責務: 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::definitions::call_unified::{CalleeBoxKind, TypeCertainty};
use crate::mir::ValueId;
#[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"));
}
}