diff --git a/src/mir/builder/calls/call_unified.rs b/src/mir/builder/calls/call_unified.rs index 5cf4bafa..9fe53f63 100644 --- a/src/mir/builder/calls/call_unified.rs +++ b/src/mir/builder/calls/call_unified.rs @@ -55,125 +55,9 @@ pub fn classify_box_kind(box_name: &str) -> crate::mir::definitions::call_unifie /// Main translation layer between builder and MIR representations /// Convert CallTarget to Callee with type resolution /// 🎯 TypeRegistry 対応: NYASH_USE_TYPE_REGISTRY=1 で registry 優先 -pub fn convert_target_to_callee( - target: CallTarget, - value_origin_newbox: &std::collections::HashMap, - value_types: &std::collections::HashMap, - type_registry: Option<&crate::mir::builder::type_registry::TypeRegistry>, -) -> Result { - let use_registry = std::env::var("NYASH_USE_TYPE_REGISTRY") - .ok() - .as_deref() == Some("1"); - - match target { - CallTarget::Global(name) => { - // Prefer explicit categories; otherwise treat as module-global function - if method_resolution::is_builtin_function(&name) { - Ok(Callee::Global(name)) - } else if method_resolution::is_extern_function(&name) { - Ok(Callee::Extern(name)) - } else { - // Module-local or static lowered function (e.g., "Box.method/N") - Ok(Callee::Global(name)) - } - }, - - CallTarget::Method { box_type, method, receiver } => { - // 🔍 Debug: trace box_name resolution (before consuming box_type) - let trace_enabled = std::env::var("NYASH_CALLEE_RESOLVE_TRACE").ok().as_deref() == Some("1"); - if trace_enabled { - eprintln!("[callee-resolve] receiver=%{} method={}", receiver.0, method); - eprintln!("[callee-resolve] explicit box_type: {:?}", box_type); - eprintln!("[callee-resolve] use_registry: {}", use_registry); - } - - let inferred_box_type = box_type.unwrap_or_else(|| { - // 🎯 TypeRegistry 対応: 優先して registry から推論 - if use_registry { - if let Some(reg) = type_registry { - let inferred = reg.infer_class(receiver, None); - if trace_enabled { - eprintln!("[callee-resolve] from_registry: {}", inferred); - // トレースチェーン表示 - let chain = reg.trace_origin(receiver); - if !chain.is_empty() { - eprintln!("[callee-resolve] trace_chain: {:?}", chain); - } - } - return inferred; - } - } - - // 従来: HashMap から推論(型情報を優先し、origin は補助とする) - let from_type = value_types - .get(&receiver) - .and_then(|t| match t { - crate::mir::MirType::Box(box_name) => Some(box_name.clone()), - _ => None, - }); - let from_origin = value_origin_newbox.get(&receiver).cloned(); - - if trace_enabled { - eprintln!("[callee-resolve] from_type: {:?}", from_type); - eprintln!("[callee-resolve] from_origin: {:?}", from_origin); - } - - // 型情報(MirType)がある場合はそれを優先し、無い場合のみ origin にフォールバックする。 - from_type - .or(from_origin) - .unwrap_or_else(|| { - if trace_enabled { - eprintln!("[callee-resolve] FALLBACK: UnknownBox"); - } - "UnknownBox".to_string() - }) - }); - - // Certainty is Known when we have explicit origin or Box型の型情報を持つ場合 - let has_box_type = value_types - .get(&receiver) - .map(|t| matches!(t, crate::mir::MirType::Box(_))) - .unwrap_or(false); - let certainty = if value_origin_newbox.contains_key(&receiver) || has_box_type { - TypeCertainty::Known - } else { - TypeCertainty::Union - }; - - // Classify box kind to prevent static/runtime mixing - let box_kind = classify_box_kind(&inferred_box_type); - - if trace_enabled { - eprintln!("[callee-resolve] inferred_box_name: {}", inferred_box_type); - eprintln!("[callee-resolve] box_kind: {:?}", box_kind); - } - - Ok(Callee::Method { - box_name: inferred_box_type, - method, - receiver: Some(receiver), - certainty, - box_kind, - }) - }, - - CallTarget::Constructor(box_type) => { - Ok(Callee::Constructor { box_type }) - }, - - CallTarget::Extern(name) => { - Ok(Callee::Extern(name)) - }, - - CallTarget::Value(func_val) => { - Ok(Callee::Value(func_val)) - }, - - CallTarget::Closure { params, captures, me_capture } => { - Ok(Callee::Closure { params, captures, me_capture }) - }, - } -} +// DEPRECATED: Moved to CalleeResolverBox::resolve() in resolver.rs +// This function is kept for reference but should not be used. +// Use CalleeResolverBox instead for all callee resolution. /// Compute effects for a call based on its callee pub fn compute_call_effects(callee: &Callee) -> EffectMask { @@ -256,43 +140,5 @@ pub fn create_mir_call( } } -/// Validate call arguments match expected signature -pub fn validate_call_args( - callee: &Callee, - args: &[ValueId], -) -> Result<(), String> { - match callee { - Callee::Global(name) => { - // Check known global functions - match name.as_str() { - "print" | "error" | "panic" => { - if args.is_empty() { - return Err(format!("{} requires at least one argument", name)); - } - } - "exit" => { - if args.len() != 1 { - return Err("exit requires exactly one argument (exit code)".to_string()); - } - } - _ => {} // Unknown functions pass through - } - }, - - Callee::Method { box_name, method, .. } => { - // Validate known methods - match (box_name.as_str(), method.as_str()) { - ("ArrayBox", "get") | ("ArrayBox", "set") => { - if args.is_empty() { - return Err(format!("ArrayBox.{} requires an index", method)); - } - } - _ => {} // Unknown methods pass through - } - }, - - _ => {} // Other callee types don't have validation yet - } - - Ok(()) -} +// DEPRECATED: validate_call_args moved to CalleeResolverBox::validate_args() in resolver.rs +// Use CalleeResolverBox instead for argument validation. diff --git a/src/mir/builder/calls/emit.rs b/src/mir/builder/calls/emit.rs index f1526928..c1fa7f8f 100644 --- a/src/mir/builder/calls/emit.rs +++ b/src/mir/builder/calls/emit.rs @@ -82,15 +82,15 @@ impl MirBuilder { ) { res?; return Ok(()); } } - // Convert CallTarget to Callee using the new module + // Convert CallTarget to Callee using CalleeResolverBox if let CallTarget::Global(ref _n) = target { /* dev trace removed */ } // Fallback: if Global target is unknown, try unique static-method mapping (name/arity) - let mut callee = match call_unified::convert_target_to_callee( - target.clone(), + let resolver = super::resolver::CalleeResolverBox::new( &self.value_origin_newbox, &self.value_types, Some(&self.type_registry), // 🎯 TypeRegistry を渡す - ) { + ); + let mut callee = match resolver.resolve(target.clone()) { Ok(c) => c, Err(e) => { if let CallTarget::Global(ref name) = target { @@ -126,7 +126,13 @@ impl MirBuilder { } // Validate call arguments - call_unified::validate_call_args(&callee, &args)?; + // 箱理論: CalleeResolverBox で引数検証 + let resolver = super::resolver::CalleeResolverBox::new( + &self.value_origin_newbox, + &self.value_types, + Some(&self.type_registry), + ); + resolver.validate_args(&callee, &args)?; // Stability guard: decide route via RouterPolicyBox (behavior-preserving rules) if let Callee::Method { box_name, method, receiver: Some(r), certainty, .. } = &callee { diff --git a/src/mir/builder/calls/mod.rs b/src/mir/builder/calls/mod.rs index 1d961f86..128d34b6 100644 --- a/src/mir/builder/calls/mod.rs +++ b/src/mir/builder/calls/mod.rs @@ -19,9 +19,10 @@ pub mod special_handlers; // New refactored modules (Box Theory Phase 1 & 2 & 25.1d) pub mod lowering; pub mod utils; -pub mod emit; // Phase 2: Call emission -pub mod build; // Phase 2: Call building -pub mod guard; // Phase 25.1d: Structural guard (static/runtime box separation) +pub mod emit; // Phase 2: Call emission +pub mod build; // Phase 2: Call building +pub mod guard; // Phase 25.1d: Structural guard (static/runtime box separation) +pub mod resolver; // Phase 25.1d: Callee resolution (CallTarget → Callee) // Re-export public interfaces pub use call_target::CallTarget; diff --git a/src/mir/builder/calls/resolver.rs b/src/mir/builder/calls/resolver.rs new file mode 100644 index 00000000..f2234891 --- /dev/null +++ b/src/mir/builder/calls/resolver.rs @@ -0,0 +1,339 @@ +/*! + * CalleeResolverBox - Callee解決専用箱 + * + * 箱理論の実践: + * - 箱にする: Callee解決ロジックを1箱に集約 + * - 境界を作る: 型情報を保持し、効率的な解決を実現 + * - 状態最小: 型情報参照のみ(変更なし) + * + * 責務: + * - CallTarget → Callee への解決 + * - Box種別分類(StaticCompiler/RuntimeData/UserDefined) + * - Call引数検証 + */ + +use crate::mir::{Callee, MirType, ValueId}; +use crate::mir::builder::CallTarget; +use crate::mir::definitions::call_unified::{CalleeBoxKind, TypeCertainty}; +use crate::mir::builder::type_registry::TypeRegistry; +use super::method_resolution; +use std::collections::HashMap; + +/// Callee解決専用箱 +/// +/// 箱理論: +/// - 単一責務: CallTarget → Callee の型安全な解決のみ +/// - 状態保持: 型情報参照を保持して効率化 +/// - ピュア解決器: 入力CallTarget → 解決・検証 → 出力Callee +pub struct CalleeResolverBox<'a> { + /// 変数のnewbox起源マップ(ValueId → Box名) + value_origin_newbox: &'a HashMap, + /// 型情報マップ(ValueId → MirType) + value_types: &'a HashMap, + /// 型レジストリ(オプショナル) + type_registry: Option<&'a TypeRegistry>, +} + +impl<'a> CalleeResolverBox<'a> { + /// 新しいCalleeResolverBoxを作成 + pub fn new( + value_origin_newbox: &'a HashMap, + value_types: &'a HashMap, + type_registry: Option<&'a TypeRegistry>, + ) -> Self { + CalleeResolverBox { + value_origin_newbox, + value_types, + type_registry, + } + } + + /// CallTarget → Callee への型安全な解決 + /// + /// 箱理論の「境界を作る」原則: + /// - Global/Method/Constructor/Extern/Value/Closureを明確に分類 + /// - 型情報を活用してbox_nameとbox_kindを決定 + /// + /// 🎯 TypeRegistry対応: NYASH_USE_TYPE_REGISTRY=1 で registry 優先 + pub fn resolve(&self, target: CallTarget) -> Result { + let use_registry = std::env::var("NYASH_USE_TYPE_REGISTRY") + .ok() + .as_deref() == Some("1"); + + match target { + CallTarget::Global(name) => { + // Prefer explicit categories; otherwise treat as module-global function + if method_resolution::is_builtin_function(&name) { + Ok(Callee::Global(name)) + } else if method_resolution::is_extern_function(&name) { + Ok(Callee::Extern(name)) + } else { + // Module-local or static lowered function (e.g., "Box.method/N") + Ok(Callee::Global(name)) + } + }, + + CallTarget::Method { box_type, method, receiver } => { + // 🔍 Debug: trace box_name resolution + let trace_enabled = std::env::var("NYASH_CALLEE_RESOLVE_TRACE") + .ok() + .as_deref() == Some("1"); + if trace_enabled { + eprintln!("[callee-resolve] receiver=%{} method={}", receiver.0, method); + eprintln!("[callee-resolve] explicit box_type: {:?}", box_type); + eprintln!("[callee-resolve] use_registry: {}", use_registry); + } + + let inferred_box_type = self.infer_box_type(receiver, box_type, trace_enabled, use_registry); + + // Certainty is Known when we have explicit origin or Box型の型情報を持つ場合 + let has_box_type = self.value_types + .get(&receiver) + .map(|t| matches!(t, MirType::Box(_))) + .unwrap_or(false); + let certainty = if self.value_origin_newbox.contains_key(&receiver) || has_box_type { + TypeCertainty::Known + } else { + TypeCertainty::Union + }; + + // Classify box kind to prevent static/runtime mixing + let box_kind = self.classify_box_kind(&inferred_box_type); + + if trace_enabled { + eprintln!("[callee-resolve] inferred_box_name: {}", inferred_box_type); + eprintln!("[callee-resolve] box_kind: {:?}", box_kind); + } + + Ok(Callee::Method { + box_name: inferred_box_type, + method, + receiver: Some(receiver), + certainty, + box_kind, + }) + }, + + CallTarget::Constructor(box_type) => { + Ok(Callee::Constructor { box_type }) + }, + + CallTarget::Extern(name) => { + Ok(Callee::Extern(name)) + }, + + CallTarget::Value(func_val) => { + Ok(Callee::Value(func_val)) + }, + + CallTarget::Closure { params, captures, me_capture } => { + Ok(Callee::Closure { params, captures, me_capture }) + }, + } + } + + /// Box種別の分類 + /// + /// 箱理論の「箱にする」原則: + /// - 静的コンパイラBox群を明示的に列挙(1箇所に集約) + /// - ランタイムDataBox群を明示的に列挙 + /// - ユーザー定義Boxをデフォルト扱い + pub fn classify_box_kind(&self, box_name: &str) -> CalleeBoxKind { + // Static compiler boxes (Stage-B, Stage-1, parsers, resolvers) + // These should ONLY appear in static method lowering, never in runtime method dispatch + match box_name { + // Stage-B compiler boxes + "StageBArgsBox" | "StageBBodyExtractorBox" | "StageBDriverBox" | + // Stage-1 using/namespace resolver boxes + "Stage1UsingResolverBox" | "BundleResolver" | + // Parser boxes + "ParserBox" | "ParserStmtBox" | "ParserExprBox" | "ParserControlBox" | + "ParserLiteralBox" | "ParserTokenBox" | + // Scanner/builder boxes + "FuncScannerBox" | "MirBuilderBox" | + // Other compiler-internal boxes + "JsonFragBox" + => CalleeBoxKind::StaticCompiler, + + // Runtime data boxes (built-in types that handle actual runtime values) + "MapBox" | "ArrayBox" | "StringBox" | "IntegerBox" | "BoolBox" | + "FloatBox" | "NullBox" | "VoidBox" | "UnknownBox" | + "FileBox" | "ConsoleBox" | "PathBox" + => CalleeBoxKind::RuntimeData, + + // Everything else is user-defined + _ => CalleeBoxKind::UserDefined, + } + } + + /// Call引数の検証 + /// + /// 既知の関数/メソッドについてarity等を検証 + pub fn validate_args(&self, callee: &Callee, args: &[ValueId]) -> Result<(), String> { + match callee { + Callee::Global(name) => { + // Check known global functions + match name.as_str() { + "print" | "error" | "panic" => { + if args.is_empty() { + return Err(format!("{} requires at least one argument", name)); + } + } + "exit" => { + if args.len() != 1 { + return Err("exit requires exactly one argument (exit code)".to_string()); + } + } + _ => {} // Unknown functions pass through + } + }, + + Callee::Method { box_name, method, .. } => { + // Validate known methods + match (box_name.as_str(), method.as_str()) { + ("ArrayBox", "get") | ("ArrayBox", "set") => { + if args.is_empty() { + return Err(format!("ArrayBox.{} requires an index", method)); + } + } + _ => {} // Unknown methods pass through + } + }, + + _ => {} // Other callee types don't have validation yet + } + + Ok(()) + } + + /// Box型の推論(内部ヘルパー) + /// + /// 優先順位: + /// 1. TypeRegistry(NYASH_USE_TYPE_REGISTRY=1の場合) + /// 2. value_types(MirType::Box) + /// 3. value_origin_newbox(起源情報) + /// 4. "UnknownBox"(フォールバック) + fn infer_box_type( + &self, + receiver: ValueId, + explicit_box_type: Option, + trace_enabled: bool, + use_registry: bool, + ) -> String { + explicit_box_type.unwrap_or_else(|| { + // 🎯 TypeRegistry 対応: 優先して registry から推論 + if use_registry { + if let Some(reg) = self.type_registry { + let inferred = reg.infer_class(receiver, None); + if trace_enabled { + eprintln!("[callee-resolve] from_registry: {}", inferred); + // トレースチェーン表示 + let chain = reg.trace_origin(receiver); + if !chain.is_empty() { + eprintln!("[callee-resolve] trace_chain: {:?}", chain); + } + } + return inferred; + } + } + + // 従来: HashMap から推論(型情報を優先し、origin は補助とする) + let from_type = self.value_types + .get(&receiver) + .and_then(|t| match t { + MirType::Box(box_name) => Some(box_name.clone()), + _ => None, + }); + let from_origin = self.value_origin_newbox.get(&receiver).cloned(); + + if trace_enabled { + eprintln!("[callee-resolve] from_type: {:?}", from_type); + eprintln!("[callee-resolve] from_origin: {:?}", from_origin); + } + + // 型情報(MirType)がある場合はそれを優先し、無い場合のみ origin にフォールバックする。 + from_type + .or(from_origin) + .unwrap_or_else(|| { + if trace_enabled { + eprintln!("[callee-resolve] FALLBACK: UnknownBox"); + } + "UnknownBox".to_string() + }) + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_classify_static_compiler_boxes() { + let value_origin = HashMap::new(); + let value_types = HashMap::new(); + let resolver = CalleeResolverBox::new(&value_origin, &value_types, None); + + // Stage-B boxes + assert_eq!(resolver.classify_box_kind("StageBArgsBox"), CalleeBoxKind::StaticCompiler); + assert_eq!(resolver.classify_box_kind("StageBDriverBox"), CalleeBoxKind::StaticCompiler); + + // Stage-1 boxes + assert_eq!(resolver.classify_box_kind("Stage1UsingResolverBox"), CalleeBoxKind::StaticCompiler); + + // Parser boxes + assert_eq!(resolver.classify_box_kind("ParserBox"), CalleeBoxKind::StaticCompiler); + } + + #[test] + fn test_classify_runtime_data_boxes() { + let value_origin = HashMap::new(); + let value_types = HashMap::new(); + let resolver = CalleeResolverBox::new(&value_origin, &value_types, None); + + assert_eq!(resolver.classify_box_kind("MapBox"), CalleeBoxKind::RuntimeData); + assert_eq!(resolver.classify_box_kind("ArrayBox"), CalleeBoxKind::RuntimeData); + assert_eq!(resolver.classify_box_kind("StringBox"), CalleeBoxKind::RuntimeData); + assert_eq!(resolver.classify_box_kind("UnknownBox"), CalleeBoxKind::RuntimeData); + } + + #[test] + fn test_classify_user_defined_boxes() { + let value_origin = HashMap::new(); + let value_types = HashMap::new(); + let resolver = CalleeResolverBox::new(&value_origin, &value_types, None); + + assert_eq!(resolver.classify_box_kind("MyCustomBox"), CalleeBoxKind::UserDefined); + assert_eq!(resolver.classify_box_kind("PersonBox"), CalleeBoxKind::UserDefined); + } + + #[test] + fn test_resolve_global() { + let value_origin = HashMap::new(); + let value_types = HashMap::new(); + let resolver = CalleeResolverBox::new(&value_origin, &value_types, None); + + let target = CallTarget::Global("print".to_string()); + let result = resolver.resolve(target).unwrap(); + + match result { + Callee::Global(name) => assert_eq!(name, "print"), + _ => panic!("Expected Global callee"), + } + } + + #[test] + fn test_resolve_constructor() { + let value_origin = HashMap::new(); + let value_types = HashMap::new(); + let resolver = CalleeResolverBox::new(&value_origin, &value_types, None); + + let target = CallTarget::Constructor("StringBox".to_string()); + let result = resolver.resolve(target).unwrap(); + + match result { + Callee::Constructor { box_type } => assert_eq!(box_type, "StringBox"), + _ => panic!("Expected Constructor callee"), + } + } +}