## 修正内容
### Core MIR/PHI (5ファイル)
- builder.rs: variable_map, value_types, value_origin_newbox
- context.rs: 3つのマップ
- loop_builder.rs: 3箇所
- loop_snapshot_manager.rs: snapshot マップ
- loop_snapshot_merge.rs: 2箇所
### MIR関連 (4ファイル)
- function.rs: FunctionMetadata.value_types
- resolver.rs: CalleeResolverBox
- guard.rs: CalleeGuardBox
- loop_common.rs: apply_increment_before_continue
### JSON Bridge (5ファイル)
- json_v0_bridge/lowering.rs
- json_v0_bridge/lowering/expr.rs
- json_v0_bridge/lowering/if_else.rs
- json_v0_bridge/lowering/merge.rs
- json_v0_bridge/lowering/try_catch.rs
- json_v0_bridge/mod.rs
### Printer & Providers (4ファイル)
- printer.rs, printer_helpers.rs
- host_providers/mir_builder.rs
- backend/mir_interpreter/handlers/extern_provider.rs
### Tests (3ファイル)
- phi_core/conservative.rs
- tests/json_program_loop.rs
- tests/mir_stage1_using_resolver_verify.rs (2テスト有効化)
## テスト結果
- mir_stage1_using_resolver_resolve_with_modules_map_verifies: 80%成功率
- 完全な決定性は未達成 (HashMap 86箇所、HashSet 63箇所が残存)
🐱 Generated with Claude Code
118 lines
4.4 KiB
Rust
118 lines
4.4 KiB
Rust
/*!
|
|
* 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::BTreeMap; // Phase 25.1: 決定性確保
|
|
|
|
/// 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: &BTreeMap<String, ValueId>, // Phase 25.1: BTreeMap化
|
|
) -> 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,
|
|
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
|
|
}
|
|
}
|