Files
hakorune/src/mir/builder/calls/method_resolution.rs

121 lines
4.3 KiB
Rust
Raw Normal View History

/*!
* Method Resolution System
*
* Type-safe function and method resolution at compile-time
* ChatGPT5 Pro design for preventing runtime string-based resolution
*/
use crate::mir::{Callee, ValueId};
use std::collections::HashMap;
/// Resolve function call target to type-safe Callee
/// Implements the core logic of compile-time function resolution
pub fn resolve_call_target(
name: &str,
current_static_box: &Option<String>,
variable_map: &HashMap<String, ValueId>,
) -> Result<Callee, String> {
// 1. Check for built-in/global functions first
if is_builtin_function(name) {
return Ok(Callee::Global(name.to_string()));
}
// 2. Check for static box method in current context
if let Some(box_name) = current_static_box {
if has_method(box_name, name) {
// Warn about potential self-recursion
if is_commonly_shadowed_method(name) {
eprintln!("{}", generate_self_recursion_warning(box_name, name));
}
return Ok(Callee::Method {
box_name: box_name.clone(),
method: name.to_string(),
receiver: None, // Static method call
certainty: crate::mir::definitions::call_unified::TypeCertainty::Known,
feat(builder): CalleeBoxKind構造ガードで静的/ランタイムBox混線を根絶 🎯 箱理論の実践: 「境界を作る」原則による構造レベル分離 ## 問題 - StageBArgsBox.resolve_src内のargs.get(i)が Stage1UsingResolverBox.getに化ける(静的Box名混入) - 未定義ValueIdエラー発生(receiver定義なし) ## 解決策(構造ガード) ✅ CalleeBoxKind enum追加 - StaticCompiler: Stage-B/Stage-1コンパイラBox - RuntimeData: MapBox/ArrayBox等ランタイムBox - UserDefined: ユーザー定義Box ✅ classify_box_kind(): Box名から種別判定 - 静的Box群を明示的に列挙(1箇所に集約) - ランタイムBox群を明示的に列挙 - 将来の拡張も容易 ✅ apply_static_runtime_guard(): 混線検出・正規化 - me-call判定(receiver型==box_name → 静的降下に委ねる) - 真の混線検出(receiver型≠box_name → 正規化) - トレースログで可視化 ## 効果 - 修正前: Invalid value ValueId(150/187) - 修正後: Unknown method 'is_space' (別issue、StringBox実装不足) - → 静的Box名混入問題を根絶! ## 箱理論原則 - ✅ 境界を作る: Static/Runtime/UserDefinedを構造的に分離 - ✅ Fail-Fast: フォールバックより明示的エラー - ✅ 箱にする: CalleeBoxKindでBox種類を1箇所に集約 ## ファイル - src/mir/definitions/call_unified.rs: CalleeBoxKind enum - src/mir/builder/calls/call_unified.rs: classify_box_kind() - src/mir/builder/calls/emit.rs: apply_static_runtime_guard() - docs/development/roadmap/phases/phase-25.1d/README.md: 箱化メモ更新 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 23:13:57 +09:00
box_kind: super::call_unified::classify_box_kind(box_name),
});
}
}
// 3. Check for local variable containing function value
if let Some(&value_id) = variable_map.get(name) {
return Ok(Callee::Value(value_id));
}
// 4. Check for external/host functions
if is_extern_function(name) {
return Ok(Callee::Extern(name.to_string()));
}
// 5. Do not assume bare `name()` refers to current static box.
// Leave it unresolved so caller can try static_method_index fallback
// or report a clear unresolved error.
// 6. Resolution failed - prevent runtime string-based resolution
Err(format!("Unresolved function: '{}'. {}", name, suggest_resolution(name)))
}
/// Check if function name is a built-in global function
pub fn is_builtin_function(name: &str) -> bool {
matches!(name,
"print" | "error" | "panic" | "exit" | "now" |
"gc_collect" | "gc_stats" |
// Math functions (handled specially)
"sin" | "cos" | "abs" | "min" | "max"
)
}
/// Check if function name is an external/host function
pub fn is_extern_function(name: &str) -> bool {
name.starts_with("nyash.") ||
name.starts_with("env.") ||
name.starts_with("system.")
}
/// Check if method is commonly shadowed (for warning generation)
pub fn is_commonly_shadowed_method(name: &str) -> bool {
matches!(name, "print" | "log" | "error" | "toString")
}
/// Generate warning about potential self-recursion
pub fn generate_self_recursion_warning(box_name: &str, method: &str) -> String {
format!(
"[Warning] Calling '{}' in static box '{}' context. \
This resolves to '{}.{}' which may cause self-recursion if called from within the same method.",
method, box_name, box_name, method
)
}
/// Suggest resolution for unresolved function
pub fn suggest_resolution(name: &str) -> String {
match name {
n if n.starts_with("console") => {
"Did you mean 'env.console.log' or 'print'?".to_string()
}
"log" | "println" => {
"Did you mean 'print' or 'env.console.log'?".to_string()
}
n if n.contains('.') => {
"Qualified names should use 'env.' prefix for external calls.".to_string()
}
_ => {
"Check function name or ensure it's in scope.".to_string()
}
}
}
/// Check if current static box has the specified method
/// TODO: Replace with proper method registry lookup
pub fn has_method(box_name: &str, method: &str) -> bool {
match box_name {
"ConsoleStd" => matches!(method, "print" | "println" | "log"),
"StringBox" => matches!(method, "upper" | "lower" | "length" | "concat" | "slice"),
"IntegerBox" => matches!(method, "add" | "sub" | "mul" | "div"),
"ArrayBox" => matches!(method, "push" | "pop" | "get" | "set" | "length"),
"MapBox" => matches!(method, "get" | "set" | "has" | "delete"),
"MathBox" => matches!(method, "sin" | "cos" | "abs" | "min" | "max"),
_ => false, // Conservative: assume no method unless explicitly known
}
}