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:
@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
195
src/mir/builder/calls/guard.rs
Normal file
195
src/mir/builder/calls/guard.rs
Normal 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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user