From a968b896581db0acf8e80600f946b5cb48ba0d14 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Mon, 10 Aug 2026 20:19:51 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=BC=82=E5=B8=B8=E5=85=9C=E5=BA=95?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E7=BB=8F=20create=5Ffrom=5Ftext=20=E6=81=A2?= =?UTF-8?q?=E5=A4=8D=E9=94=99=E8=AF=AF=E7=B1=BB=E5=9E=8B=EF=BC=88=E4=B8=8D?= =?UTF-8?q?=E5=A1=8C=E7=BC=A9=E6=99=AE=E9=80=9A=20Error=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_builtins/src/array.rs | 26 +++---------------- crates/oxide_builtins/src/error.rs | 26 +++++++++++++++++++ crates/oxide_vm/src/async_from_sync.rs | 12 ++++----- crates/oxide_vm/src/async_func.rs | 6 ++--- crates/oxide_vm/src/async_generator.rs | 10 +++---- crates/oxide_vm/src/generator.rs | 6 ++--- crates/oxide_vm/src/promise.rs | 36 +++++++++++++------------- crates/oxide_vm/src/vm.rs | 2 +- 8 files changed, 65 insertions(+), 59 deletions(-) diff --git a/crates/oxide_builtins/src/array.rs b/crates/oxide_builtins/src/array.rs index 578bb6bd..286aa8ed 100644 --- a/crates/oxide_builtins/src/array.rs +++ b/crates/oxide_builtins/src/array.rs @@ -155,31 +155,11 @@ pub(crate) fn invoke_native_callback( Ok(value) => NativeResult::Ok(value), Err(err) => match vm.take_uncaught_value() { Some(original) => NativeResult::Err(original), - None => NativeResult::Err(callback_error_from_text(vm, &err)), + None => NativeResult::Err(crate::error::create_from_text(vm, &err)), }, } } -fn callback_error_from_text(vm: &mut H, err: &str) -> JsValue { - let err = err.strip_prefix("uncaught ").unwrap_or(err); - if let Some(msg) = err.strip_prefix("TypeError: ") { - return crate::error::create_type_error(vm, msg); - } - if let Some(msg) = err.strip_prefix("ReferenceError: ") { - return crate::error::create_reference_error(vm, msg); - } - if let Some(msg) = err.strip_prefix("RangeError: ") { - return crate::error::create_range_error(vm, msg); - } - if let Some(msg) = err.strip_prefix("SyntaxError: ") { - return crate::error::create_syntax_error(vm, msg); - } - if let Some(msg) = err.strip_prefix("Error: ") { - return crate::error::create_error(vm, msg); - } - crate::error::create_error(vm, err) -} - fn unexpected_tail_call_error(vm: &mut H) -> NativeResult { NativeResult::Err(crate::error::create_type_error(vm, "unexpected tail call in array callback")) } @@ -412,9 +392,9 @@ pub fn array_from(vm: &mut H, args: &[u8]) -> NativeResult { NativeResult::Ok(JsValue::from_js_object(a_ptr)) } -/// 引擎调用边界抛出的错误恢复为原始异常值(透传),否则按错误文本构造普通错误。 +/// 引擎调用边界抛出的错误恢复为原始异常值(透传),否则按错误文本构造对应 kind 的错误。 fn from_engine_error(vm: &mut H, err: &str) -> JsValue { - vm.take_uncaught_value().unwrap_or_else(|| callback_error_from_text(vm, err)) + vm.take_uncaught_value().unwrap_or_else(|| crate::error::create_from_text(vm, err)) } /// 按构造函数 C 构造 Array.from 的结果对象:C 可构造时以 C.prototype 分配 `this` diff --git a/crates/oxide_builtins/src/error.rs b/crates/oxide_builtins/src/error.rs index 5eddb7e9..2c3fbe17 100644 --- a/crates/oxide_builtins/src/error.rs +++ b/crates/oxide_builtins/src/error.rs @@ -65,6 +65,32 @@ pub fn create_error(host: &mut H, msg: &str) -> JsValue { create_kind_error(host, "Error", msg) } +/// 从错误文本(形如 `TypeError: msg` / `ReferenceError: msg`)解析类型前缀并创建 +/// 对应 kind 的错误对象;无前缀时创建普通 Error。 +/// +/// # 使用场景 +/// 异常传播链中错误对象被降级为文本(error_text 输出、`last_uncaught_value` 被 +/// 嵌套覆盖后的兜底路径)时,据此恢复错误类型,避免全部塌缩成普通 Error。 +pub fn create_from_text(host: &mut H, text: &str) -> JsValue { + let text = text.strip_prefix("uncaught ").unwrap_or(text); + for (kind, prefix) in [ + ("TypeError", "TypeError: "), + ("ReferenceError", "ReferenceError: "), + ("RangeError", "RangeError: "), + ("SyntaxError", "SyntaxError: "), + ("URIError", "URIError: "), + ("EvalError", "EvalError: "), + ] { + if let Some(msg) = text.strip_prefix(prefix) { + return create_kind_error(host, kind, msg); + } + } + if let Some(msg) = text.strip_prefix("Error: ") { + return create_kind_error(host, "Error", msg); + } + create_error(host, text) +} + /// 创建一个带指定 message 的 ReferenceError 对象。 pub fn create_reference_error(host: &mut H, msg: &str) -> JsValue { create_kind_error(host, "ReferenceError", msg) diff --git a/crates/oxide_vm/src/async_from_sync.rs b/crates/oxide_vm/src/async_from_sync.rs index 6775fccb..6400c9b4 100644 --- a/crates/oxide_vm/src/async_from_sync.rs +++ b/crates/oxide_vm/src/async_from_sync.rs @@ -163,7 +163,7 @@ fn continue_async_from_sync(vm: &mut Vm, inner: JsValue, result: Result NativeResult { let exc = vm .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); return NativeResult::Err(exc); } }; @@ -344,7 +344,7 @@ fn async_from_sync_return(vm: &mut Vm, args: &[u8]) -> NativeResult { let exc = vm .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); return NativeResult::Err(exc); } }; @@ -377,7 +377,7 @@ fn async_from_sync_throw(vm: &mut Vm, args: &[u8]) -> NativeResult { let exc = vm .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); return NativeResult::Err(exc); } }; diff --git a/crates/oxide_vm/src/async_func.rs b/crates/oxide_vm/src/async_func.rs index ab50fda2..dd584b2a 100644 --- a/crates/oxide_vm/src/async_func.rs +++ b/crates/oxide_vm/src/async_func.rs @@ -167,7 +167,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); self.finish_async(state_ptr, Err(exc))?; self.restore_inline_state(saved); Ok(()) @@ -248,7 +248,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); self.finish_async(state_ptr, Err(exc))?; self.restore_inline_state(saved); Ok(()) @@ -390,7 +390,7 @@ fn async_await_resume_closure(vm: &mut Vm, args: &[u8]) -> NativeResult { }; match vm.resume_async(ctx, mode) { Ok(()) => NativeResult::Ok(JsValue::undefined()), - Err(e) => NativeResult::Err(oxide_builtins::error::create_error(vm, &e)), + Err(e) => NativeResult::Err(oxide_builtins::error::create_from_text(vm, &e)), } } diff --git a/crates/oxide_vm/src/async_generator.rs b/crates/oxide_vm/src/async_generator.rs index 52672a25..08197d01 100644 --- a/crates/oxide_vm/src/async_generator.rs +++ b/crates/oxide_vm/src/async_generator.rs @@ -176,7 +176,7 @@ impl Vm { Ok(v) => { oxide_builtins::error::create_error(self, &format!("async generator initialization failed: {v:?}")) } - Err(e) => oxide_builtins::error::create_error(self, &e), + Err(e) => oxide_builtins::error::create_from_text(self, &e), }); let kind = self.thrown_error_kind(exc); unsafe { (*state_ptr).phase = AsyncGenPhase::Completed }; @@ -221,7 +221,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); return Err(exc); } } @@ -337,7 +337,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd); return self.finish_async_gen_exc(state_ptr, saved, gen_val, exc); } @@ -467,7 +467,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); self.finish_async_gen_exc(state_ptr, saved, gen_val, exc) } } @@ -629,7 +629,7 @@ fn async_gen_await_resume_closure(vm: &mut Vm, args: &[u8]) -> NativeResult { } match vm.resume_async_generator(ctx) { Ok(()) => NativeResult::Ok(JsValue::undefined()), - Err(e) => NativeResult::Err(oxide_builtins::error::create_error(vm, &e)), + Err(e) => NativeResult::Err(oxide_builtins::error::create_from_text(vm, &e)), } } diff --git a/crates/oxide_vm/src/generator.rs b/crates/oxide_vm/src/generator.rs index 3774318a..48950dcb 100644 --- a/crates/oxide_vm/src/generator.rs +++ b/crates/oxide_vm/src/generator.rs @@ -187,7 +187,7 @@ impl Vm { // 参数初始化抛错/异常结束:恢复调用方上下文后重新抛出。 let exc = self.last_uncaught_value.take().unwrap_or_else(|| match result { Ok(v) => oxide_builtins::error::create_error(self, &format!("generator initialization failed: {v:?}")), - Err(e) => oxide_builtins::error::create_error(self, &e), + Err(e) => oxide_builtins::error::create_from_text(self, &e), }); let kind = self.thrown_error_kind(exc); unsafe { (*state_ptr).phase = GeneratorPhase::Completed }; @@ -296,7 +296,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); self.restore_inline_state(saved); self.native_call_depth -= 1; let state = unsafe { &mut *state_ptr }; @@ -409,7 +409,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); let state = unsafe { &mut *state_ptr }; state.phase = GeneratorPhase::Completed; state.result = JsValue::undefined(); diff --git a/crates/oxide_vm/src/promise.rs b/crates/oxide_vm/src/promise.rs index 87e31e66..98297bc8 100644 --- a/crates/oxide_vm/src/promise.rs +++ b/crates/oxide_vm/src/promise.rs @@ -212,7 +212,7 @@ impl Vm { Err(e) => Err(self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e))), + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e))), } } @@ -327,7 +327,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); return self.reject_promise(promise, exc); } }; @@ -415,7 +415,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); return Err(exc); } }; @@ -429,7 +429,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); return Err(exc); } Ok(promise) @@ -545,7 +545,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); let _ = self.call_function_sync(reject, JsValue::undefined(), &[exc]); } } @@ -563,7 +563,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); let _ = self.call_function_sync(reject, JsValue::undefined(), &[exc]); } } @@ -713,7 +713,7 @@ fn promise_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult { let exc = vm .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); let _ = vm.reject_promise(this_val, exc); NativeResult::Ok(this_val) } @@ -742,7 +742,7 @@ fn promise_resolve_closure(vm: &mut Vm, args: &[u8]) -> NativeResult { let exc = vm .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); let _ = vm.reject_promise(promise, exc); } NativeResult::Ok(JsValue::undefined()) @@ -825,7 +825,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)); return Err(exc); } }; @@ -837,7 +837,7 @@ impl Vm { Err(e) => Err(self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, &e))), + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e))), } } @@ -1082,7 +1082,7 @@ fn promise_finally_handler(vm: &mut Vm, args: &[u8]) -> NativeResult { let exc = vm .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); NativeResult::Err(exc) } } @@ -1102,7 +1102,7 @@ fn promise_static_resolve(vm: &mut Vm, args: &[u8]) -> NativeResult { let exc = vm .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); return NativeResult::Err(exc); } }; @@ -1121,7 +1121,7 @@ fn promise_static_resolve(vm: &mut Vm, args: &[u8]) -> NativeResult { let exc = vm .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); NativeResult::Err(exc) } } @@ -1141,7 +1141,7 @@ fn promise_static_reject(vm: &mut Vm, args: &[u8]) -> NativeResult { let exc = vm .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); NativeResult::Err(exc) } } @@ -1217,7 +1217,7 @@ fn perform_promise_combine( let exc = vm .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); let _ = vm.call_function_sync(reject, JsValue::undefined(), &[exc]); return Ok(promise); } @@ -1415,7 +1415,7 @@ fn agg_call_resolve(vm: &mut Vm, record: JsValue, arg: JsValue) { let exc = vm .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); let reject = agg_record_val(vm, record, AGG_REJECT_PROP); let _ = vm.call_function_sync(reject, JsValue::undefined(), &[exc]); } @@ -1425,7 +1425,7 @@ fn agg_call_resolve(vm: &mut Vm, record: JsValue, arg: JsValue) { fn agg_engine_error(vm: &mut Vm, err: &str) -> JsValue { vm.last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, err)) + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, err)) } /// IteratorClose:调用迭代器的 `return()`(可调用时),忽略其抛错。 @@ -1548,7 +1548,7 @@ fn aggregate_error_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult { let exc = vm .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e)); return NativeResult::Err(exc); } }; diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index fc0fb94a..8842a986 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -437,7 +437,7 @@ impl Vm { let exc = self .last_uncaught_value .take() - .unwrap_or_else(|| oxide_builtins::error::create_error(self, err)); + .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, err)); let kind = self.thrown_error_kind(exc); self.exception_value = Some(exc); self.pending_error_kind = Some(kind);