fix: Fix NyashParser import path and improve BoxCall fallback

- Fix NyashParser import path in vm.rs tests
- Improve BoxCall fallback logic for plugin/builtin methods
- Add proper function existence checks before lowering to Call

This ensures plugin Box methods correctly fall back to BoxCall
when the corresponding user-defined function doesn't exist.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-08-20 23:07:16 +09:00
parent 64167def8f
commit af32896574
2 changed files with 36 additions and 32 deletions

View File

@ -1072,7 +1072,7 @@ impl Default for VM {
mod tests {
use super::*;
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirType, EffectMask, BasicBlock};
use crate::NyashParser;
use crate::parser::NyashParser;
use crate::runtime::NyashRuntime;
use crate::core::model::BoxDeclaration as CoreBoxDecl;
use crate::interpreter::SharedState;

View File

@ -991,27 +991,10 @@ impl MirBuilder {
// Optimization: If the object is a direct `new ClassName(...)`, lower to a direct Call
if let ASTNode::New { class, .. } = object {
// Build function name: "{Class}.{method}/{argc}"
// Build function name and only lower to Call if the function exists (user-defined)
let func_name = format!("{}.{}{}", class, method, format!("/{}", arg_values.len()));
// Create a constant for the function name
let func_val = self.value_gen.next();
self.emit_instruction(MirInstruction::Const { dst: func_val, value: ConstValue::String(func_name) })?;
// Prepare args: me + user args
let mut call_args = Vec::with_capacity(arg_values.len() + 1);
call_args.push(object_value);
call_args.extend(arg_values);
// Emit direct Call
self.emit_instruction(MirInstruction::Call {
dst: Some(result_id),
func: func_val,
args: call_args,
effects: EffectMask::READ.add(Effect::ReadHeap),
})?;
Ok(result_id)
} else {
// If the object originates from a NewBox in this function, we can lower to Call as well
if let Some(class_name) = self.value_origin_newbox.get(&object_value).cloned() {
let func_name = format!("{}.{}{}", class_name, method, format!("/{}", arg_values.len()));
let can_lower = if let Some(ref module) = self.current_module { module.functions.contains_key(&func_name) } else { false };
if can_lower {
let func_val = self.value_gen.next();
self.emit_instruction(MirInstruction::Const { dst: func_val, value: ConstValue::String(func_name) })?;
let mut call_args = Vec::with_capacity(arg_values.len() + 1);
@ -1023,19 +1006,40 @@ impl MirBuilder {
args: call_args,
effects: EffectMask::READ.add(Effect::ReadHeap),
})?;
Ok(result_id)
} else {
// Fallback: Emit a BoxCall instruction for regular method calls
self.emit_instruction(MirInstruction::BoxCall {
dst: Some(result_id),
box_val: object_value,
method,
args: arg_values,
effects: EffectMask::READ.add(Effect::ReadHeap), // Method calls may have side effects
})?;
Ok(result_id)
return Ok(result_id);
}
// else fall through to BoxCall below
} else {
// If the object originates from a NewBox in this function, we can lower to Call as well
if let Some(class_name) = self.value_origin_newbox.get(&object_value).cloned() {
let func_name = format!("{}.{}{}", class_name, method, format!("/{}", arg_values.len()));
let can_lower = if let Some(ref module) = self.current_module { module.functions.contains_key(&func_name) } else { false };
if can_lower {
let func_val = self.value_gen.next();
self.emit_instruction(MirInstruction::Const { dst: func_val, value: ConstValue::String(func_name) })?;
let mut call_args = Vec::with_capacity(arg_values.len() + 1);
call_args.push(object_value);
call_args.extend(arg_values);
self.emit_instruction(MirInstruction::Call {
dst: Some(result_id),
func: func_val,
args: call_args,
effects: EffectMask::READ.add(Effect::ReadHeap),
})?;
return Ok(result_id);
}
}
}
// Fallback: Emit a BoxCall instruction for regular or plugin/builtin method calls
self.emit_instruction(MirInstruction::BoxCall {
dst: Some(result_id),
box_val: object_value,
method,
args: arg_values,
effects: EffectMask::READ.add(Effect::ReadHeap), // Method calls may have side effects
})?;
Ok(result_id)
}
/// Build from expression: from Parent.method(arguments)