refactor(builder): 箱化 - CalleeGuardBox抽出(構造ガード専用箱)

🎯 箱理論の実践: 単一責務の箱を作る

## 箱化内容
 CalleeGuardBox(約150行、テスト込み約200行)
  - 責務: 構造ガード専任(静的Box/ランタイムBox混線防止)
  - 状態: value_typesのみ保持(最小化)
  - ピュア関数的: Callee入力 → 検証・変換 → Callee出力

## 実装
- src/mir/builder/calls/guard.rs: 新ファイル
  - CalleeGuardBox::apply_static_runtime_guard()
  - CalleeGuardBox::is_me_call()
  - CalleeGuardBox::get_box_type()
  - 単体テスト3件追加(me-call検出、正規化)

- src/mir/builder/calls/emit.rs: 箱化移行
  - emit_unified_call_impl内でCalleeGuardBox使用
  - 古いapply_static_runtime_guardメソッド削除(約50行削減)

- src/mir/builder/calls/mod.rs: モジュール追加
  - pub mod guard;(Phase 25.1d完了マーク)

## 箱理論原則
 箱にする: 構造ガード機能を1箱に集約
 境界を作る: MirBuilderから分離、独立した責務
 戻せる: 独立箱なので切り離し・差し替え可能
 テスト容易: 単体テスト3件で検証済み

## 効果
- コード整理: emit.rs 約50行削減
- 保守性向上: 構造ガードロジックが1ファイルに集約
- テスト品質: 単体テストで挙動保証
- 拡張容易: 将来の構造ガード追加が容易

## テスト結果
-  CalleeGuardBox単体テスト 3件パス
-  既存テスト mir_stageb_like系 パス
-  ビルド成功(0エラー)

🤖 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-17 23:21:36 +09:00
parent 73844dbe04
commit e67c8dc8d5
3 changed files with 203 additions and 58 deletions

View File

@ -107,8 +107,9 @@ impl MirBuilder {
callee = self.materialize_receiver_in_callee(callee)?; callee = self.materialize_receiver_in_callee(callee)?;
// Structural guard: prevent static compiler boxes from being called with runtime receivers // Structural guard: prevent static compiler boxes from being called with runtime receivers
// If box_kind is StaticCompiler but receiver has a runtime Box type, normalize to runtime // 箱理論: CalleeGuardBox による構造的分離
callee = self.apply_static_runtime_guard(callee)?; let guard = super::guard::CalleeGuardBox::new(&self.value_types);
callee = guard.apply_static_runtime_guard(callee)?;
// Emit resolve.choose for method callee (dev-only; default OFF) // Emit resolve.choose for method callee (dev-only; default OFF)
if let Callee::Method { box_name, method, certainty, .. } = &callee { if let Callee::Method { box_name, method, certainty, .. } = &callee {
@ -455,59 +456,6 @@ impl MirBuilder {
}) })
} }
/// Structural guard: prevent static compiler boxes from mixing with runtime data boxes // ✅ 箱化完了: apply_static_runtime_guard → CalleeGuardBox::apply_static_runtime_guard
/// // 構造ガードロジックは src/mir/builder/calls/guard.rs に移動済み
/// 箱理論の「境界を作る」原則: Stage-B/Stage-1コンパイラBoxとランタイムDataBoxを
/// 構造レベルで分離し、型メタデータの混入を防ぐ。
///
/// If box_kind is StaticCompiler but receiver has a runtime Box type (MapBox/ArrayBox/etc.),
/// normalize box_name to the runtime type. This prevents cases like:
/// - Stage1UsingResolverBox.get where receiver is actually MapBox
/// - StageBArgsBox.length where receiver is actually ArrayBox
///
/// This is a Fail-Fast structural guard, not a fallback.
fn apply_static_runtime_guard(&self, callee: Callee) -> Result<Callee, String> {
use crate::mir::definitions::call_unified::CalleeBoxKind;
if let Callee::Method { ref box_name, ref method, receiver: Some(recv), certainty, box_kind } = callee {
// Only apply guard if box_kind is StaticCompiler
if box_kind == CalleeBoxKind::StaticCompiler {
// Check if receiver has a Box type
if let Some(crate::mir::MirType::Box(receiver_box)) = self.value_types.get(&recv) {
let trace_enabled = std::env::var("NYASH_CALLEE_RESOLVE_TRACE").ok().as_deref() == Some("1");
// If receiver box type matches the static box name, this is a me-call
// Let it through for static method lowering (don't normalize)
if receiver_box == box_name {
if trace_enabled {
eprintln!("[static-runtime-guard] ME-CALL detected:");
eprintln!(" {}.{} with receiver type: {} (same as box_name)", box_name, method, receiver_box);
eprintln!(" → Allowing for static method lowering");
}
return Ok(callee); // Pass through unchanged
}
// Otherwise, this is a true mix-up: runtime box with static box name
// Normalize to the runtime box type
if trace_enabled {
eprintln!("[static-runtime-guard] CORRECTING mix-up:");
eprintln!(" Original: {}.{} (box_kind=StaticCompiler)", box_name, method);
eprintln!(" Receiver %{} has runtime type: {}", recv.0, receiver_box);
eprintln!(" Normalized: {}.{}", receiver_box, method);
}
return Ok(Callee::Method {
box_name: receiver_box.clone(),
method: method.clone(),
receiver: Some(recv),
certainty,
box_kind: CalleeBoxKind::RuntimeData, // Switch to runtime
});
}
}
}
// No guard needed, return as-is
Ok(callee)
}
} }

View File

@ -0,0 +1,195 @@
/*!
* CalleeGuardBox - 構造ガード専用箱
*
* 箱理論の実践:
* - 箱にする: 構造ガード機能を1箱に集約
* - 境界を作る: 静的Box/ランタイムBoxの混線を構造的に防ぐ
* - Fail-Fast: フォールバックより明示的エラー
*
* 責務:
* - Callee::Methodの静的Box/ランタイムBox混線検出・正規化
* - me-call判定receiver型==box_name
* - receiver実体化の保証
*/
use crate::mir::{Callee, MirType, ValueId};
use crate::mir::definitions::call_unified::CalleeBoxKind;
use std::collections::HashMap;
/// 構造ガード専用箱
///
/// 箱理論:
/// - 単一責務: Calleeの構造検証・正規化のみ
/// - 状態最小: value_typesのみ保持型情報参照用
/// - ピュア関数的: 入力Callee → 検証・変換 → 出力Callee
pub struct CalleeGuardBox<'a> {
/// 型情報マップValueId → MirType
value_types: &'a HashMap<ValueId, MirType>,
}
impl<'a> CalleeGuardBox<'a> {
/// 新しいCalleeGuardBoxを作成
pub fn new(value_types: &'a HashMap<ValueId, MirType>) -> Self {
CalleeGuardBox { value_types }
}
/// 静的Box/ランタイムBox混線を検出・正規化
///
/// 箱理論の「境界を作る」原則:
/// - Stage-B/Stage-1コンパイラBoxとランタイムDataBoxを構造的に分離
///
/// ロジック:
/// 1. box_kind==StaticCompiler かつ receiver型==同一Box名
/// → me-call判定、静的メソッド降下に委ねるそのまま通す
/// 2. box_kind==StaticCompiler かつ receiver型==異なるランタイムBox
/// → 正規化MapBox/ArrayBoxなど実際のruntime型に修正
/// 3. それ以外 → そのまま通す
///
/// 実例:
/// - StageBArgsBox.resolve_src内のargs.get(i)がStage1UsingResolverBox.getに
/// 化けるのを防ぐargs型はMapBox/ArrayBox → 正規化)
pub fn apply_static_runtime_guard(&self, callee: Callee) -> Result<Callee, String> {
if let Callee::Method { ref box_name, ref method, receiver: Some(recv), certainty, box_kind } = callee {
// Only apply guard if box_kind is StaticCompiler
if box_kind == CalleeBoxKind::StaticCompiler {
// Check if receiver has a Box type
if let Some(MirType::Box(receiver_box)) = self.value_types.get(&recv) {
let trace_enabled = std::env::var("NYASH_CALLEE_RESOLVE_TRACE")
.ok()
.as_deref() == Some("1");
// If receiver box type matches the static box name, this is a me-call
// Let it through for static method lowering (don't normalize)
if receiver_box == box_name {
if trace_enabled {
eprintln!("[static-runtime-guard] ME-CALL detected:");
eprintln!(" {}.{} with receiver type: {} (same as box_name)", box_name, method, receiver_box);
eprintln!(" → Allowing for static method lowering");
}
return Ok(callee); // Pass through unchanged
}
// Otherwise, this is a true mix-up: runtime box with static box name
// Normalize to the runtime box type
if trace_enabled {
eprintln!("[static-runtime-guard] CORRECTING mix-up:");
eprintln!(" Original: {}.{} (box_kind=StaticCompiler)", box_name, method);
eprintln!(" Receiver %{} has runtime type: {}", recv.0, receiver_box);
eprintln!(" Normalized: {}.{}", receiver_box, method);
}
return Ok(Callee::Method {
box_name: receiver_box.clone(),
method: method.clone(),
receiver: Some(recv),
certainty,
box_kind: CalleeBoxKind::RuntimeData, // Switch to runtime
});
}
}
}
// No guard needed, return as-is
Ok(callee)
}
/// receiver型の検証ヘルパー
///
/// 指定されたreceiverがBox型を持っているか確認
pub fn has_box_type(&self, receiver: ValueId) -> bool {
matches!(self.value_types.get(&receiver), Some(MirType::Box(_)))
}
/// receiver型の取得ヘルパー
///
/// 指定されたreceiverのBox型名を返す存在しない場合はNone
pub fn get_box_type(&self, receiver: ValueId) -> Option<&String> {
match self.value_types.get(&receiver) {
Some(MirType::Box(box_name)) => Some(box_name),
_ => None,
}
}
/// me-call判定
///
/// box_name と receiver型が一致するか判定
/// (静的メソッド呼び出しの検出用)
pub fn is_me_call(&self, box_name: &str, receiver: ValueId) -> bool {
match self.get_box_type(receiver) {
Some(recv_box) => recv_box == box_name,
None => false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_me_call_detection() {
let mut value_types = HashMap::new();
value_types.insert(ValueId::new(10), MirType::Box("StageBArgsBox".to_string()));
let guard = CalleeGuardBox::new(&value_types);
// Same box name → me-call
assert!(guard.is_me_call("StageBArgsBox", ValueId::new(10)));
// Different box name → not me-call
assert!(!guard.is_me_call("Stage1UsingResolverBox", ValueId::new(10)));
// No type info → not me-call
assert!(!guard.is_me_call("StageBArgsBox", ValueId::new(999)));
}
#[test]
fn test_static_runtime_guard_me_call() {
use crate::mir::definitions::call_unified::TypeCertainty;
let mut value_types = HashMap::new();
value_types.insert(ValueId::new(10), MirType::Box("StageBArgsBox".to_string()));
let guard = CalleeGuardBox::new(&value_types);
let callee = Callee::Method {
box_name: "StageBArgsBox".to_string(),
method: "process".to_string(),
receiver: Some(ValueId::new(10)),
certainty: TypeCertainty::Known,
box_kind: CalleeBoxKind::StaticCompiler,
};
// me-call → should pass through unchanged
let result = guard.apply_static_runtime_guard(callee.clone()).unwrap();
assert_eq!(result, callee);
}
#[test]
fn test_static_runtime_guard_normalization() {
use crate::mir::definitions::call_unified::TypeCertainty;
let mut value_types = HashMap::new();
value_types.insert(ValueId::new(10), MirType::Box("MapBox".to_string()));
let guard = CalleeGuardBox::new(&value_types);
let callee = Callee::Method {
box_name: "Stage1UsingResolverBox".to_string(),
method: "get".to_string(),
receiver: Some(ValueId::new(10)),
certainty: TypeCertainty::Known,
box_kind: CalleeBoxKind::StaticCompiler,
};
// Mix-up → should normalize to MapBox
let result = guard.apply_static_runtime_guard(callee).unwrap();
match result {
Callee::Method { box_name, box_kind, .. } => {
assert_eq!(box_name, "MapBox");
assert_eq!(box_kind, CalleeBoxKind::RuntimeData);
}
_ => panic!("Expected Method callee"),
}
}
}

View File

@ -5,6 +5,7 @@
//! - utils: ユーティリティresolve/parse/extract //! - utils: ユーティリティresolve/parse/extract
//! - emit: Call命令発行統一Call/Legacy Call ✅ Phase 2完了 //! - emit: Call命令発行統一Call/Legacy Call ✅ Phase 2完了
//! - build: Call構築function call/method call ✅ Phase 2完了 //! - build: Call構築function call/method call ✅ Phase 2完了
//! - guard: 構造ガード静的Box/ランタイムBox混線防止 ✅ Phase 25.1d完了
// Existing modules (already implemented elsewhere) // Existing modules (already implemented elsewhere)
pub mod annotation; pub mod annotation;
@ -15,11 +16,12 @@ pub mod function_lowering;
pub mod method_resolution; pub mod method_resolution;
pub mod special_handlers; pub mod special_handlers;
// New refactored modules (Box Theory Phase 1 & 2) // New refactored modules (Box Theory Phase 1 & 2 & 25.1d)
pub mod lowering; pub mod lowering;
pub mod utils; pub mod utils;
pub mod emit; // Phase 2: Call emission pub mod emit; // Phase 2: Call emission
pub mod build; // Phase 2: Call building pub mod build; // Phase 2: Call building
pub mod guard; // Phase 25.1d: Structural guard (static/runtime box separation)
// Re-export public interfaces // Re-export public interfaces
pub use call_target::CallTarget; pub use call_target::CallTarget;