refactor: complete error message unification (Phase 3.5)

Migrate remaining 45 error generation patterns to unified helpers:
- calls.rs: 13 sites → 0
- extern_provider.rs: 9 sites → 0
- externals.rs: 5 sites → 0
- boxes_plugin.rs: 5 sites → 0
- boxes.rs: 5 sites → 0
- boxes_string.rs: 4 sites → 0
- boxes_instance.rs: 2 sites → 0
- mod.rs + boxes_array.rs: 2 sites → 0

Error patterns now 100% unified:
- All 80 InvalidInstruction sites use helpers (100%)
- Consistent error formatting across entire codebase
- Single source of truth for error messages

Code reduction:
- Phase 3.5: 50-70 lines saved
- Cumulative (Phase 1+2+3+3.5): 200-267 lines removed (6-8% handlers)
- Total patterns unified: 192 (destination 60 + args 52 + errors 80)

Benefits:
- 100% error message consistency achieved
- Easy to modify error formats globally
- Foundation for i18n support ready
- Improved maintainability and testability

Test results: ✓ Build successful, Phase 21.0 smoke tests passing
Related: Phase 21.0 refactoring milestone complete
Risk: Low (error messages only, behavior preserved)
This commit is contained in:
nyash-codex
2025-11-06 23:34:46 +09:00
parent 0287020a5b
commit 22b668927e
9 changed files with 56 additions and 111 deletions

View File

@ -11,7 +11,7 @@ impl MirInterpreter {
) -> Result<(), VMError> { ) -> Result<(), VMError> {
// Provider Lock guard (受け口・既定は挙動不変) // Provider Lock guard (受け口・既定は挙動不変)
if let Err(e) = crate::runtime::provider_lock::guard_before_new_box(box_type) { if let Err(e) = crate::runtime::provider_lock::guard_before_new_box(box_type) {
return Err(VMError::InvalidInstruction(e)); return Err(self.err_invalid(e));
} }
let mut converted: Vec<Box<dyn NyashBox>> = Vec::with_capacity(args.len()); let mut converted: Vec<Box<dyn NyashBox>> = Vec::with_capacity(args.len());
for vid in args { for vid in args {
@ -22,9 +22,7 @@ impl MirInterpreter {
.lock() .lock()
.unwrap() .unwrap()
.create_box(box_type, &converted) .create_box(box_type, &converted)
.map_err(|e| { .map_err(|e| self.err_with_context(&format!("NewBox {}", box_type), &e.to_string()))?;
VMError::InvalidInstruction(format!("NewBox {} failed: {}", box_type, e))
})?;
// Store created instance first so 'me' can be passed to birth // Store created instance first so 'me' can be passed to birth
let created_vm = VMValue::from_nyash_box(created); let created_vm = VMValue::from_nyash_box(created);
self.regs.insert(dst, created_vm.clone()); self.regs.insert(dst, created_vm.clone());
@ -74,10 +72,10 @@ impl MirInterpreter {
} }
} }
Err(e) => { Err(e) => {
return Err(VMError::InvalidInstruction(format!( return Err(self.err_with_context(
"PluginInvoke {}.{} failed: {:?}", &format!("PluginInvoke {}.{}", p.box_type, method),
p.box_type, method, e &format!("{:?}", e)
))) ))
} }
} }
Ok(()) Ok(())
@ -88,11 +86,7 @@ impl MirInterpreter {
} }
Ok(()) Ok(())
} else { } else {
Err(VMError::InvalidInstruction(format!( Err(self.err_method_not_found(&recv_box.type_name(), method))
"PluginInvoke unsupported on {} for method {}",
recv_box.type_name(),
method
)))
} }
} }
@ -188,7 +182,7 @@ impl MirInterpreter {
} }
if user_instance_class.is_some() && !crate::config::env::vm_allow_user_instance_boxcall() { if user_instance_class.is_some() && !crate::config::env::vm_allow_user_instance_boxcall() {
let cls = user_instance_class.unwrap(); let cls = user_instance_class.unwrap();
return Err(VMError::InvalidInstruction(format!( return Err(self.err_invalid(format!(
"User Instance BoxCall disallowed in prod: {}.{} (enable builder rewrite)", "User Instance BoxCall disallowed in prod: {}.{} (enable builder rewrite)",
cls, method cls, method
))); )));

View File

@ -32,7 +32,7 @@ pub(super) fn try_handle_array_box(
return Ok(true); return Ok(true);
} }
"pop" => { "pop" => {
if !args.is_empty() { return Err(VMError::InvalidInstruction("pop expects 0 args".into())); } if !args.is_empty() { return Err(this.err_invalid("pop expects 0 args")); }
let ret = ab.pop(); let ret = ab.pop();
this.write_result(dst, VMValue::from_nyash_box(ret)); this.write_result(dst, VMValue::from_nyash_box(ret));
return Ok(true); return Ok(true);

View File

@ -92,7 +92,7 @@ pub(super) fn try_handle_instance_box(
// Dev assert: forbid birth(me==Void) // Dev assert: forbid birth(me==Void)
if method == "birth" && crate::config::env::using_is_dev() { if method == "birth" && crate::config::env::using_is_dev() {
if matches!(recv_vm, VMValue::Void) { if matches!(recv_vm, VMValue::Void) {
return Err(VMError::InvalidInstruction("Dev assert: birth(me==Void) is forbidden".into())); return Err(this.err_invalid("Dev assert: birth(me==Void) is forbidden"));
} }
} }
argv.push(recv_vm.clone()); argv.push(recv_vm.clone());
@ -127,7 +127,7 @@ pub(super) fn try_handle_instance_box(
let mut argv: Vec<VMValue> = Vec::with_capacity(1 + args.len()); let mut argv: Vec<VMValue> = Vec::with_capacity(1 + args.len());
if method == "birth" && crate::config::env::using_is_dev() { if method == "birth" && crate::config::env::using_is_dev() {
if matches!(recv_vm, VMValue::Void) { if matches!(recv_vm, VMValue::Void) {
return Err(VMError::InvalidInstruction("Dev assert: birth(me==Void) is forbidden".into())); return Err(this.err_invalid("Dev assert: birth(me==Void) is forbidden"));
} }
} }
argv.push(recv_vm.clone()); argv.push(recv_vm.clone());

View File

@ -60,10 +60,10 @@ pub(super) fn invoke_plugin_box(
} }
Ok(()) Ok(())
} }
Err(e) => Err(VMError::InvalidInstruction(format!( Err(e) => Err(this.err_with_context(
"BoxCall {}.{} failed: {:?}", &format!("BoxCall {}.{}", p.box_type, method),
p.box_type, method, e &format!("{:?}", e)
))), )),
} }
} else if let Some(string_box) = recv_box } else if let Some(string_box) = recv_box
.as_any() .as_any()
@ -80,9 +80,7 @@ pub(super) fn invoke_plugin_box(
} }
Ok(()) Ok(())
} else { } else {
Err(VMError::InvalidInstruction( Err(this.err_invalid("lastIndexOf requires 1 argument"))
"lastIndexOf requires 1 argument".into(),
))
} }
} }
"indexOf" | "find" => { "indexOf" | "find" => {
@ -94,15 +92,10 @@ pub(super) fn invoke_plugin_box(
} }
Ok(()) Ok(())
} else { } else {
Err(VMError::InvalidInstruction( Err(this.err_invalid("indexOf/find requires 1 argument"))
"indexOf/find requires 1 argument".into(),
))
} }
} }
_ => Err(VMError::InvalidInstruction(format!( _ => Err(this.err_method_not_found("StringBox", method)),
"BoxCall method {} not supported on StringBox",
method
))),
} }
} else { } else {
// Special-case: minimal runtime fallback for common InstanceBox methods when // Special-case: minimal runtime fallback for common InstanceBox methods when
@ -209,10 +202,6 @@ pub(super) fn invoke_plugin_box(
_ => {} _ => {}
} }
} }
Err(VMError::InvalidInstruction(format!( Err(this.err_method_not_found(&recv_box.type_name(), method))
"BoxCall unsupported on {}.{}",
recv_box.type_name(),
method
)))
} }
} }

View File

@ -72,8 +72,8 @@ pub(super) fn try_handle_string_box(
(n, from.max(0) as usize) (n, from.max(0) as usize)
} }
_ => { _ => {
return Err(VMError::InvalidInstruction( return Err(this.err_invalid(
"indexOf expects 1 or 2 args (search [, fromIndex])".into(), "indexOf expects 1 or 2 args (search [, fromIndex])"
)); ));
} }
}; };
@ -144,8 +144,8 @@ pub(super) fn try_handle_string_box(
(s, e) (s, e)
} }
_ => { _ => {
return Err(VMError::InvalidInstruction( return Err(this.err_invalid(
"substring expects 1 or 2 args (start [, end])".into(), "substring expects 1 or 2 args (start [, end])"
)); ));
} }
}; };
@ -172,7 +172,7 @@ pub(super) fn try_handle_string_box(
let s = this.reg_load(args[0])?.to_string(); let s = this.reg_load(args[0])?.to_string();
s.chars().next() s.chars().next()
} else { } else {
return Err(VMError::InvalidInstruction("is_digit_char expects 0 or 1 arg".into())); return Err(this.err_invalid("is_digit_char expects 0 or 1 arg"));
}; };
let is_digit = ch_opt.map(|c| c.is_ascii_digit()).unwrap_or(false); let is_digit = ch_opt.map(|c| c.is_ascii_digit()).unwrap_or(false);
this.write_result(dst, VMValue::Bool(is_digit)); this.write_result(dst, VMValue::Bool(is_digit));
@ -185,7 +185,7 @@ pub(super) fn try_handle_string_box(
let s = this.reg_load(args[0])?.to_string(); let s = this.reg_load(args[0])?.to_string();
s.chars().next() s.chars().next()
} else { } else {
return Err(VMError::InvalidInstruction("is_hex_digit_char expects 0 or 1 arg".into())); return Err(this.err_invalid("is_hex_digit_char expects 0 or 1 arg"));
}; };
let is_hex = ch_opt.map(|c| c.is_ascii_hexdigit()).unwrap_or(false); let is_hex = ch_opt.map(|c| c.is_ascii_hexdigit()).unwrap_or(false);
this.write_result(dst, VMValue::Bool(is_hex)); this.write_result(dst, VMValue::Bool(is_hex));

View File

@ -424,15 +424,10 @@ impl MirInterpreter {
if let Some(s) = first_arg_str { if let Some(s) = first_arg_str {
match crate::host_providers::mir_builder::program_json_to_mir_json(&s) { match crate::host_providers::mir_builder::program_json_to_mir_json(&s) {
Ok(out) => Ok(VMValue::String(out)), Ok(out) => Ok(VMValue::String(out)),
Err(e) => Err(VMError::InvalidInstruction(format!( Err(e) => Err(self.err_with_context("env.mirbuilder.emit", &e.to_string())),
"env.mirbuilder.emit: {}",
e
))),
} }
} else { } else {
Err(VMError::InvalidInstruction( Err(self.err_invalid("extern_invoke env.mirbuilder.emit expects 1 arg"))
"extern_invoke env.mirbuilder.emit expects 1 arg".into(),
))
} }
} }
("env.codegen", "emit_object") => { ("env.codegen", "emit_object") => {
@ -445,15 +440,10 @@ impl MirInterpreter {
}; };
match crate::host_providers::llvm_codegen::mir_json_to_object(&s, opts) { match crate::host_providers::llvm_codegen::mir_json_to_object(&s, opts) {
Ok(p) => Ok(VMValue::String(p.to_string_lossy().into_owned())), Ok(p) => Ok(VMValue::String(p.to_string_lossy().into_owned())),
Err(e) => Err(VMError::InvalidInstruction(format!( Err(e) => Err(self.err_with_context("env.codegen.emit_object", &e.to_string())),
"env.codegen.emit_object: {}",
e
))),
} }
} else { } else {
Err(VMError::InvalidInstruction( Err(self.err_invalid("extern_invoke env.codegen.emit_object expects 1 arg"))
"extern_invoke env.codegen.emit_object expects 1 arg".into(),
))
} }
} }
("env.codegen", "link_object") => { ("env.codegen", "link_object") => {
@ -611,7 +601,7 @@ impl MirInterpreter {
if std::env::var("HAKO_CABI_TRACE").ok().as_deref() == Some("1") { if std::env::var("HAKO_CABI_TRACE").ok().as_deref() == Some("1") {
eprintln!("[hb:unsupported:calls] {}.{}", name, method); eprintln!("[hb:unsupported:calls] {}.{}", name, method);
} }
Err(VMError::InvalidInstruction(format!( Err(self.err_invalid(format!(
"hostbridge.extern_invoke unsupported for {}.{} [calls]", "hostbridge.extern_invoke unsupported for {}.{} [calls]",
name, method name, method
))) )))
@ -705,9 +695,7 @@ impl MirInterpreter {
let new_str = format!("{}{}", s, arg_val.to_string()); let new_str = format!("{}{}", s, arg_val.to_string());
Ok(VMValue::String(new_str)) Ok(VMValue::String(new_str))
} else { } else {
Err(VMError::InvalidInstruction( Err(self.err_invalid("concat requires 1 argument"))
"concat requires 1 argument".into(),
))
} }
} }
"replace" => { "replace" => {
@ -716,9 +704,7 @@ impl MirInterpreter {
let new = self.reg_load(args[1])?.to_string(); let new = self.reg_load(args[1])?.to_string();
Ok(VMValue::String(s.replace(&old, &new))) Ok(VMValue::String(s.replace(&old, &new)))
} else { } else {
Err(VMError::InvalidInstruction( Err(self.err_invalid("replace requires 2 arguments"))
"replace requires 2 arguments".into(),
))
} }
} }
"indexOf" => { "indexOf" => {
@ -727,9 +713,7 @@ impl MirInterpreter {
let idx = s.find(&needle).map(|i| i as i64).unwrap_or(-1); let idx = s.find(&needle).map(|i| i as i64).unwrap_or(-1);
Ok(VMValue::Integer(idx)) Ok(VMValue::Integer(idx))
} else { } else {
Err(VMError::InvalidInstruction( Err(self.err_invalid("indexOf requires 1 argument"))
"indexOf requires 1 argument".into(),
))
} }
} }
"lastIndexOf" => { "lastIndexOf" => {
@ -738,9 +722,7 @@ impl MirInterpreter {
let idx = s.rfind(&needle).map(|i| i as i64).unwrap_or(-1); let idx = s.rfind(&needle).map(|i| i as i64).unwrap_or(-1);
Ok(VMValue::Integer(idx)) Ok(VMValue::Integer(idx))
} else { } else {
Err(VMError::InvalidInstruction( Err(self.err_invalid("lastIndexOf requires 1 argument"))
"lastIndexOf requires 1 argument".into(),
))
} }
} }
"substring" => { "substring" => {
@ -774,9 +756,7 @@ impl MirInterpreter {
let result_box = string_box.lastIndexOf(&needle); let result_box = string_box.lastIndexOf(&needle);
Ok(VMValue::from_nyash_box(result_box)) Ok(VMValue::from_nyash_box(result_box))
} else { } else {
Err(VMError::InvalidInstruction( Err(self.err_invalid("lastIndexOf requires 1 argument"))
"lastIndexOf requires 1 argument".into(),
))
} }
} }
"indexOf" | "find" => { "indexOf" | "find" => {
@ -785,9 +765,7 @@ impl MirInterpreter {
let result_box = string_box.find(&needle); let result_box = string_box.find(&needle);
Ok(VMValue::from_nyash_box(result_box)) Ok(VMValue::from_nyash_box(result_box))
} else { } else {
Err(VMError::InvalidInstruction( Err(self.err_invalid("indexOf/find requires 1 argument"))
"indexOf/find requires 1 argument".into(),
))
} }
} }
_ => Err(self.err_method_not_found("StringBox", method)), _ => Err(self.err_method_not_found("StringBox", method)),
@ -811,17 +789,13 @@ impl MirInterpreter {
) { ) {
Ok(Some(ret)) => Ok(VMValue::from_nyash_box(ret)), Ok(Some(ret)) => Ok(VMValue::from_nyash_box(ret)),
Ok(None) => Ok(VMValue::Void), Ok(None) => Ok(VMValue::Void),
Err(e) => Err(VMError::InvalidInstruction(format!( Err(e) => Err(self.err_with_context(
"Plugin method {}.{} failed: {:?}", &format!("Plugin method {}.{}", p.box_type, method),
p.box_type, method, e &format!("{:?}", e)
))), )),
} }
} else { } else {
Err(VMError::InvalidInstruction(format!( Err(self.err_method_not_found(&box_ref.type_name(), method))
"Method {} not supported on BoxRef({})",
method,
box_ref.type_name()
)))
} }
} }
_ => Err(self.err_with_context("method call", &format!("{} not supported on {:?}", method, receiver))), _ => Err(self.err_with_context("method call", &format!("{} not supported on {:?}", method, receiver))),

View File

@ -82,7 +82,7 @@ impl MirInterpreter {
// Only supported on C-API route; expect 1 or 2 args: obj_path [, exe_out] // Only supported on C-API route; expect 1 or 2 args: obj_path [, exe_out]
let obj_path = match args.get(0) { let obj_path = match args.get(0) {
Some(v) => match self.reg_load(*v) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) }, Some(v) => match self.reg_load(*v) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) },
None => return Some(Err(VMError::InvalidInstruction("env.codegen.link_object expects 1+ args".into()))), None => return Some(Err(self.err_invalid("env.codegen.link_object expects 1+ args"))),
}; };
let exe_out = match args.get(1) { let exe_out = match args.get(1) {
Some(v) => Some(match self.reg_load(*v) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) }), Some(v) => Some(match self.reg_load(*v) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) }),
@ -114,9 +114,7 @@ impl MirInterpreter {
eprintln!("[hb:entry:provider] hostbridge.extern_invoke"); eprintln!("[hb:entry:provider] hostbridge.extern_invoke");
} }
if args.len() < 2 { if args.len() < 2 {
return Some(Err(VMError::InvalidInstruction( return Some(Err(self.err_invalid("extern_invoke expects at least 2 args")));
"extern_invoke expects at least 2 args".into(),
)));
} }
let name = match self.reg_load(args[0]) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) }; let name = match self.reg_load(args[0]) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) };
let method = match self.reg_load(args[1]) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) }; let method = match self.reg_load(args[1]) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) };
@ -186,7 +184,7 @@ impl MirInterpreter {
_ => (v.to_string(), None), _ => (v.to_string(), None),
} }
} else { } else {
return Some(Err(VMError::InvalidInstruction("extern_invoke env.codegen.link_object expects args array".into()))); return Some(Err(self.err_invalid("extern_invoke env.codegen.link_object expects args array")));
}; };
if std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() != Some("1") || if std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() != Some("1") ||
std::env::var("HAKO_V1_EXTERN_PROVIDER_C_ABI").ok().as_deref() != Some("1") { std::env::var("HAKO_V1_EXTERN_PROVIDER_C_ABI").ok().as_deref() != Some("1") {
@ -204,15 +202,10 @@ impl MirInterpreter {
if let Some(s) = first_arg_str { if let Some(s) = first_arg_str {
match crate::host_providers::mir_builder::program_json_to_mir_json(&s) { match crate::host_providers::mir_builder::program_json_to_mir_json(&s) {
Ok(out) => Ok(VMValue::String(Self::patch_mir_json_version(&out))), Ok(out) => Ok(VMValue::String(Self::patch_mir_json_version(&out))),
Err(e) => Err(VMError::InvalidInstruction(format!( Err(e) => Err(self.err_with_context("env.mirbuilder.emit", &e.to_string())),
"env.mirbuilder.emit: {}",
e
))),
} }
} else { } else {
Err(VMError::InvalidInstruction( Err(self.err_invalid("extern_invoke env.mirbuilder.emit expects 1 arg"))
"extern_invoke env.mirbuilder.emit expects 1 arg".into(),
))
} }
} }
("env.codegen", "emit_object") => { ("env.codegen", "emit_object") => {
@ -225,15 +218,10 @@ impl MirInterpreter {
}; };
match crate::host_providers::llvm_codegen::mir_json_to_object(&s, opts) { match crate::host_providers::llvm_codegen::mir_json_to_object(&s, opts) {
Ok(p) => Ok(VMValue::String(p.to_string_lossy().into_owned())), Ok(p) => Ok(VMValue::String(p.to_string_lossy().into_owned())),
Err(e) => Err(VMError::InvalidInstruction(format!( Err(e) => Err(self.err_with_context("env.codegen.emit_object", &e.to_string())),
"env.codegen.emit_object: {}",
e
))),
} }
} else { } else {
Err(VMError::InvalidInstruction( Err(self.err_invalid("extern_invoke env.codegen.emit_object expects 1 arg"))
"extern_invoke env.codegen.emit_object expects 1 arg".into(),
))
} }
} }
("env.codegen", "link_object") => { ("env.codegen", "link_object") => {
@ -267,7 +255,7 @@ impl MirInterpreter {
} }
let objs = match obj_s { let objs = match obj_s {
Some(s) => s, Some(s) => s,
None => return Some(Err(VMError::InvalidInstruction("extern_invoke env.codegen.link_object expects args".into()))), None => return Some(Err(self.err_invalid("extern_invoke env.codegen.link_object expects args"))),
}; };
if std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() != Some("1") || if std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() != Some("1") ||
std::env::var("HAKO_V1_EXTERN_PROVIDER_C_ABI").ok().as_deref() != Some("1") { std::env::var("HAKO_V1_EXTERN_PROVIDER_C_ABI").ok().as_deref() != Some("1") {
@ -285,7 +273,7 @@ impl MirInterpreter {
if std::env::var("HAKO_CABI_TRACE").ok().as_deref() == Some("1") { if std::env::var("HAKO_CABI_TRACE").ok().as_deref() == Some("1") {
eprintln!("[hb:unsupported:provider] {}.{}", name, method); eprintln!("[hb:unsupported:provider] {}.{}", name, method);
} }
Err(VMError::InvalidInstruction(format!( Err(self.err_invalid(format!(
"hostbridge.extern_invoke unsupported for {}.{} [provider]", "hostbridge.extern_invoke unsupported for {}.{} [provider]",
name, method name, method
))) )))

View File

@ -155,7 +155,7 @@ impl MirInterpreter {
// Note: This branch is used for ExternCall form; provider toggles must be ON. // Note: This branch is used for ExternCall form; provider toggles must be ON.
if std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() != Some("1") || if std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() != Some("1") ||
std::env::var("HAKO_V1_EXTERN_PROVIDER_C_ABI").ok().as_deref() != Some("1") { std::env::var("HAKO_V1_EXTERN_PROVIDER_C_ABI").ok().as_deref() != Some("1") {
return Err(VMError::InvalidInstruction("env.codegen.link_object: C-API route disabled".into())); return Err(self.err_invalid("env.codegen.link_object: C-API route disabled"));
} }
// Extract array payload // Extract array payload
let (obj_path, exe_out) = if let Some(a2) = args.get(2) { let (obj_path, exe_out) = if let Some(a2) = args.get(2) {
@ -177,13 +177,13 @@ impl MirInterpreter {
_ => (v.to_string(), None), _ => (v.to_string(), None),
} }
} else { } else {
return Err(VMError::InvalidInstruction("extern_invoke env.codegen.link_object expects args array".into())); return Err(self.err_invalid("extern_invoke env.codegen.link_object expects args array"));
}; };
let extra = std::env::var("HAKO_AOT_LDFLAGS").ok(); let extra = std::env::var("HAKO_AOT_LDFLAGS").ok();
let obj = std::path::PathBuf::from(obj_path); let obj = std::path::PathBuf::from(obj_path);
let exe = exe_out.map(std::path::PathBuf::from).unwrap_or_else(|| std::env::temp_dir().join("hako_link_out.exe")); let exe = exe_out.map(std::path::PathBuf::from).unwrap_or_else(|| std::env::temp_dir().join("hako_link_out.exe"));
crate::host_providers::llvm_codegen::link_object_capi(&obj, &exe, extra.as_deref()) crate::host_providers::llvm_codegen::link_object_capi(&obj, &exe, extra.as_deref())
.map_err(|e| VMError::InvalidInstruction(format!("env.codegen.link_object: {}", e)))?; .map_err(|e| self.err_with_context("env.codegen.link_object", &e.to_string()))?;
self.write_result(dst, VMValue::String(exe.to_string_lossy().into_owned())); self.write_result(dst, VMValue::String(exe.to_string_lossy().into_owned()));
Ok(()) Ok(())
} }
@ -195,9 +195,9 @@ impl MirInterpreter {
} }
return Ok(()); return Ok(());
} }
return Err(VMError::InvalidInstruction("hostbridge.extern_invoke unsupported [externals]".into())); return Err(self.err_invalid("hostbridge.extern_invoke unsupported [externals]"));
} }
_ => Err(VMError::InvalidInstruction(format!( _ => Err(self.err_invalid(format!(
"ExternCall {}.{} not supported", "ExternCall {}.{} not supported",
iface, method iface, method
))), ))),

View File

@ -96,7 +96,7 @@ impl MirInterpreter {
| MirInstruction::Safepoint | MirInstruction::Safepoint
| MirInstruction::Nop => {} | MirInstruction::Nop => {}
other => { other => {
return Err(VMError::InvalidInstruction(format!( return Err(self.err_invalid(format!(
"MIR interp: unimplemented instruction: {:?}", "MIR interp: unimplemented instruction: {:?}",
other other
))) )))