diff --git a/Cargo.lock b/Cargo.lock index ff6e75d31..9a79bf333 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -699,6 +699,7 @@ version = "0.2.0" dependencies = [ "bytes", "deno_core", + "deno_error", "deno_ops", "pretty_assertions", "prettyplease", diff --git a/core/00_infra.js b/core/00_infra.js index 0c5e1cde1..39e7a3c66 100644 --- a/core/00_infra.js +++ b/core/00_infra.js @@ -17,7 +17,7 @@ Promise, PromiseReject, PromiseResolve, - PromisePrototypeThen, + PromisePrototypeCatch, RangeError, ReferenceError, SafeArrayIterator, @@ -133,18 +133,22 @@ MapPrototypeSet(promiseMap, oldPromiseId, oldPromise); } - const promise = new Promise((resolve) => { - promiseRing[idx] = resolve; + const promise = new Promise((resolve, reject) => { + promiseRing[idx] = [resolve, reject]; }); - const wrappedPromise = PromisePrototypeThen( + const wrappedPromise = PromisePrototypeCatch( promise, - unwrapOpError(), + (res) => { + // recreate the stacktrace and strip eventLoopTick() calls from stack trace + ErrorCaptureStackTrace(res, eventLoopTick); + throw res; + }, ); wrappedPromise[promiseIdSymbol] = promiseId; return wrappedPromise; } - function __resolvePromise(promiseId, res) { + function __resolvePromise(promiseId, res, isOk) { // Check if out of ring bounds, fallback to map const outOfBounds = promiseId < nextPromiseId - RING_SIZE; if (outOfBounds) { @@ -153,7 +157,11 @@ throw "Missing promise in map @ " + promiseId; } MapPrototypeDelete(promiseMap, promiseId); - promise(res); + if (isOk) { + promise[0](res); + } else { + promise[1](res); + } } else { // Otherwise take from ring const idx = promiseId % RING_SIZE; @@ -162,7 +170,11 @@ throw "Missing promise in ring @ " + promiseId; } promiseRing[idx] = NO_PROMISE; - promise(res); + if (isOk) { + promise[0](res); + } else { + promise[1](res); + } } } @@ -177,38 +189,6 @@ return promiseRing[idx] != NO_PROMISE; } - function unwrapOpError() { - return (res) => { - // .$err_class_name is a special key that should only exist on errors - const className = res?.$err_class_name; - if (!className) { - return res; - } - - const errorBuilder = errorMap[className]; - const err = errorBuilder ? errorBuilder(res.message) : new Error( - `Unregistered error class: "${className}"\n ${res.message}\n Classes of errors returned from ops should be registered via Deno.core.registerErrorClass().`, - ); - - if (res.additional_properties) { - for ( - const property of new SafeArrayIterator(res.additional_properties) - ) { - const key = property[0]; - if (!(key in err)) { - ObjectDefineProperty(err, key, { - value: property[1], - writable: false, - }); - } - } - } - // Strip eventLoopTick() calls from stack trace - ErrorCaptureStackTrace(err, eventLoopTick); - throw err; - }; - } - function setUpAsyncStub(opName, originalOp, maybeProto) { let fn; diff --git a/core/01_core.js b/core/01_core.js index 19f054d85..17db6e53a 100644 --- a/core/01_core.js +++ b/core/01_core.js @@ -161,10 +161,12 @@ // responses of async ops. function eventLoopTick() { // First respond to all pending ops. - for (let i = 0; i < arguments.length - 3; i += 2) { + for (let i = 0; i < arguments.length - 3; i += 3) { const promiseId = arguments[i]; - const res = arguments[i + 1]; - __resolvePromise(promiseId, res); + const isOk = arguments[i + 1]; + const res = arguments[i + 2]; + + __resolvePromise(promiseId, res, isOk); } // Drain nextTick queue if there's a tick scheduled. if (arguments[arguments.length - 1]) { diff --git a/core/error.rs b/core/error.rs index e70e397a3..53c4d2ce7 100644 --- a/core/error.rs +++ b/core/error.rs @@ -1,8 +1,6 @@ // Copyright 2018-2025 the Deno authors. MIT license. pub use super::modules::ModuleConcreteError; -pub use super::runtime::op_driver::OpError; -pub use super::runtime::op_driver::OpErrorWrapper; pub use crate::io::ResourceError; pub use crate::modules::ModuleLoaderError; use crate::runtime::v8_static_strings; diff --git a/core/examples/hello_world.rs b/core/examples/hello_world.rs index 8d55cf937..025a26f99 100644 --- a/core/examples/hello_world.rs +++ b/core/examples/hello_world.rs @@ -7,7 +7,7 @@ use deno_core::*; /// An op for summing an array of numbers. The op-layer automatically /// deserializes inputs and serializes the returned Result & value. #[op2] -fn op_sum(#[serde] nums: Vec) -> Result { +fn op_sum(#[serde] nums: Vec) -> Result { // Sum inputs let sum = nums.iter().fold(0.0, |a, v| a + v); // return as a Result diff --git a/core/examples/op2.rs b/core/examples/op2.rs index e0422cfc9..2898d3452 100644 --- a/core/examples/op2.rs +++ b/core/examples/op2.rs @@ -1,7 +1,6 @@ // Copyright 2018-2025 the Deno authors. MIT license. use anyhow::Context; -use deno_core::error::OpError; use deno_core::*; use std::rc::Rc; @@ -9,7 +8,7 @@ use std::rc::Rc; fn op_use_state( state: &mut OpState, #[global] callback: v8::Global, -) -> Result<(), OpError> { +) -> Result<(), deno_error::JsErrorBox> { state.put(callback); Ok(()) } diff --git a/core/ops_builtin.rs b/core/ops_builtin.rs index f296dcebc..e075d22fd 100644 --- a/core/ops_builtin.rs +++ b/core/ops_builtin.rs @@ -2,7 +2,8 @@ use crate::error::exception_to_err_result; use crate::error::format_file_name; -use crate::error::OpError; +use crate::error::CoreError; +use crate::error::ResourceError; use crate::io::AdaptiveBufferStrategy; use crate::io::BufMutView; use crate::io::BufView; @@ -176,14 +177,14 @@ pub async fn op_void_async() {} #[allow(clippy::unused_async)] #[op2(async)] -pub async fn op_error_async() -> Result<(), OpError> { - Err(JsErrorBox::generic("error").into()) +pub async fn op_error_async() -> Result<(), JsErrorBox> { + Err(JsErrorBox::generic("error")) } #[allow(clippy::unused_async)] #[op2(async(deferred), fast)] -pub async fn op_error_async_deferred() -> Result<(), OpError> { - Err(JsErrorBox::generic("error").into()) +pub async fn op_error_async_deferred() -> Result<(), JsErrorBox> { + Err(JsErrorBox::generic("error")) } #[allow(clippy::unused_async)] @@ -195,7 +196,7 @@ pub async fn op_void_async_deferred() {} pub fn op_close( state: Rc>, #[smi] rid: ResourceId, -) -> Result<(), OpError> { +) -> Result<(), ResourceError> { let resource = state.borrow_mut().resource_table.take_any(rid)?; resource.close(); Ok(()) @@ -212,7 +213,10 @@ pub fn op_try_close(state: Rc>, #[smi] rid: ResourceId) { /// Builtin utility to print to stdout/stderr #[op2(fast)] -pub fn op_print(#[string] msg: &str, is_err: bool) -> Result<(), OpError> { +pub fn op_print( + #[string] msg: &str, + is_err: bool, +) -> Result<(), std::io::Error> { if is_err { stderr().write_all(msg.as_bytes())?; stderr().flush().unwrap(); @@ -244,7 +248,7 @@ pub fn op_wasm_streaming_feed( state: Rc>, #[smi] rid: ResourceId, #[buffer] bytes: &[u8], -) -> Result<(), OpError> { +) -> Result<(), ResourceError> { let wasm_streaming = state .borrow_mut() .resource_table @@ -260,7 +264,7 @@ pub fn op_wasm_streaming_set_url( state: &mut OpState, #[smi] rid: ResourceId, #[string] url: &str, -) -> Result<(), OpError> { +) -> Result<(), ResourceError> { let wasm_streaming = state.resource_table.get::(rid)?; @@ -274,14 +278,14 @@ async fn op_read( state: Rc>, #[smi] rid: ResourceId, #[buffer] buf: JsBuffer, -) -> Result { - let resource = state.borrow().resource_table.get_any(rid)?; +) -> Result { + let resource = state + .borrow() + .resource_table + .get_any(rid) + .map_err(JsErrorBox::from_err)?; let view = BufMutView::from(buf); - resource - .read_byob(view) - .await - .map(|(n, _)| n as u32) - .map_err(|err| err.into()) + resource.read_byob(view).await.map(|(n, _)| n as u32) } #[op2(async)] @@ -289,8 +293,12 @@ async fn op_read( async fn op_read_all( state: Rc>, #[smi] rid: ResourceId, -) -> Result { - let resource = state.borrow().resource_table.get_any(rid)?; +) -> Result { + let resource = state + .borrow() + .resource_table + .get_any(rid) + .map_err(JsErrorBox::from_err)?; let (min, maybe_max) = resource.size_hint(); let mut buffer_strategy = @@ -324,8 +332,12 @@ async fn op_write( state: Rc>, #[smi] rid: ResourceId, #[buffer] buf: JsBuffer, -) -> Result { - let resource = state.borrow().resource_table.get_any(rid)?; +) -> Result { + let resource = state + .borrow() + .resource_table + .get_any(rid) + .map_err(JsErrorBox::from_err)?; let view = BufView::from(buf); let resp = resource.write(view).await?; Ok(resp.nwritten() as u32) @@ -336,12 +348,13 @@ fn op_read_sync( state: Rc>, #[smi] rid: ResourceId, #[buffer] data: &mut [u8], -) -> Result { - let resource = state.borrow_mut().resource_table.get_any(rid)?; - resource - .read_byob_sync(data) - .map(|n| n as u32) - .map_err(|err| err.into()) +) -> Result { + let resource = state + .borrow_mut() + .resource_table + .get_any(rid) + .map_err(JsErrorBox::from_err)?; + resource.read_byob_sync(data).map(|n| n as u32) } #[op2(fast)] @@ -349,8 +362,12 @@ fn op_write_sync( state: Rc>, #[smi] rid: ResourceId, #[buffer] data: &[u8], -) -> Result { - let resource = state.borrow_mut().resource_table.get_any(rid)?; +) -> Result { + let resource = state + .borrow_mut() + .resource_table + .get_any(rid) + .map_err(JsErrorBox::from_err)?; let nwritten = resource.write_sync(data)?; Ok(nwritten as u32) } @@ -360,8 +377,12 @@ async fn op_write_all( state: Rc>, #[smi] rid: ResourceId, #[buffer] buf: JsBuffer, -) -> Result<(), OpError> { - let resource = state.borrow().resource_table.get_any(rid)?; +) -> Result<(), JsErrorBox> { + let resource = state + .borrow() + .resource_table + .get_any(rid) + .map_err(JsErrorBox::from_err)?; let view = BufView::from(buf); resource.write_all(view).await?; Ok(()) @@ -372,11 +393,13 @@ async fn op_write_type_error( state: Rc>, #[smi] rid: ResourceId, #[string] error: String, -) -> Result<(), OpError> { - let resource = state.borrow().resource_table.get_any(rid)?; - resource - .write_error(&deno_error::JsErrorBox::type_error(error)) - .await?; +) -> Result<(), JsErrorBox> { + let resource = state + .borrow() + .resource_table + .get_any(rid) + .map_err(JsErrorBox::from_err)?; + resource.write_error(&JsErrorBox::type_error(error)).await?; Ok(()) } @@ -384,9 +407,13 @@ async fn op_write_type_error( async fn op_shutdown( state: Rc>, #[smi] rid: ResourceId, -) -> Result<(), OpError> { - let resource = state.borrow().resource_table.get_any(rid)?; - resource.shutdown().await.map_err(|err| err.into()) +) -> Result<(), JsErrorBox> { + let resource = state + .borrow() + .resource_table + .get_any(rid) + .map_err(JsErrorBox::from_err)?; + resource.shutdown().await } #[op2] @@ -424,7 +451,7 @@ fn op_encode_binary_string(#[buffer] s: &[u8]) -> ByteString { fn op_is_terminal( state: &mut OpState, #[smi] rid: ResourceId, -) -> Result { +) -> Result { let handle = state.resource_table.get_handle(rid)?; Ok(handle.is_terminal()) } @@ -434,7 +461,7 @@ async fn do_load_job<'s>( module_map_rc: Rc, specifier: &str, code: Option, -) -> Result { +) -> Result { if let Some(code) = code { module_map_rc .new_es_module(scope, false, specifier.to_owned(), code, false, None) @@ -487,8 +514,7 @@ async fn do_load_job<'s>( false, false, ) - .unwrap_err() - .into(), + .unwrap_err(), ); } } @@ -554,7 +580,7 @@ fn op_import_sync<'s>( scope: &mut v8::HandleScope<'s>, #[string] specifier: &str, #[string] code: Option, -) -> Result, OpError> { +) -> Result, CoreError> { let module_map_rc = JsRealm::module_map_from(scope); // no js execution within block_on @@ -594,8 +620,7 @@ fn op_import_sync<'s>( false, false, ) - .unwrap_err() - .into(), + .unwrap_err(), ); } } diff --git a/core/ops_builtin_v8.rs b/core/ops_builtin_v8.rs index 83e45dd11..ff617fe81 100644 --- a/core/ops_builtin_v8.rs +++ b/core/ops_builtin_v8.rs @@ -1,8 +1,9 @@ // Copyright 2018-2025 the Deno authors. MIT license. use crate::error::is_instance_of_error; +use crate::error::CoreError; use crate::error::JsError; -use crate::error::OpError; +use crate::io::ResourceError; use crate::modules::script_origin; use crate::op2; use crate::ops_builtin::WasmStreamingResource; @@ -193,11 +194,9 @@ pub fn op_timer_unref(scope: &mut v8::HandleScope, id: f64) { pub fn op_lazy_load_esm( scope: &mut v8::HandleScope, #[string] module_specifier: String, -) -> Result, OpError> { +) -> Result, CoreError> { let module_map_rc = JsRealm::module_map_from(scope); - module_map_rc - .lazy_load_esm_module(scope, &module_specifier) - .map_err(|e| e.into()) + module_map_rc.lazy_load_esm_module(scope, &module_specifier) } // We run in a `nofast` op here so we don't get put into a `DisallowJavascriptExecutionScope` and we're @@ -264,13 +263,13 @@ pub fn op_eval_context<'a>( source: v8::Local<'a, v8::Value>, #[string] specifier: String, host_defined_options: Option>, -) -> Result, OpError> { +) -> Result, JsErrorBox> { let out = v8::Array::new(scope, 2); let state = JsRuntime::state_from(scope); let tc_scope = &mut v8::TryCatch::new(scope); let source = v8::Local::::try_from(source) .map_err(|_| JsErrorBox::type_error("Invalid source"))?; - let specifier = resolve_url(&specifier)?; + let specifier = resolve_url(&specifier).map_err(JsErrorBox::from_err)?; let specifier_v8 = v8::String::new(tc_scope, specifier.as_str()).unwrap(); let host_defined_options = match host_defined_options { Some(array) => { @@ -279,7 +278,7 @@ pub fn op_eval_context<'a>( let value = array.get_index(tc_scope, i).unwrap(); let value = value .try_cast::() - .map_err(crate::error::DataError)?; + .map_err(|e| JsErrorBox::from_err(crate::error::DataError(e)))?; output.set(tc_scope, i as _, value); } Some(output.into()) @@ -381,7 +380,7 @@ pub fn op_eval_context<'a>( pub fn op_encode<'a>( scope: &mut v8::HandleScope<'a>, text: v8::Local<'a, v8::Value>, -) -> Result, OpError> { +) -> Result, JsErrorBox> { let text = v8::Local::::try_from(text) .map_err(|_| JsErrorBox::type_error("Invalid argument"))?; let text_str = serde_v8::to_utf8(text, scope); @@ -398,7 +397,7 @@ pub fn op_encode<'a>( pub fn op_decode<'a>( scope: &mut v8::HandleScope<'a>, #[buffer] zero_copy: &[u8], -) -> Result, OpError> { +) -> Result, JsErrorBox> { let buf = &zero_copy; // Strip BOM @@ -419,7 +418,7 @@ pub fn op_decode<'a>( // - https://github.com/v8/v8/blob/d68fb4733e39525f9ff0a9222107c02c28096e2a/include/v8.h#L3277-L3278 match v8::String::new_from_utf8(scope, buf, v8::NewStringType::Normal) { Some(text) => Ok(text), - None => Err(JsErrorBox::range_error("string too long").into()), + None => Err(JsErrorBox::range_error("string too long")), } } @@ -599,7 +598,7 @@ pub fn op_serialize( transferred_array_buffers: Option>, for_storage: bool, error_callback: Option>, -) -> Result, OpError> { +) -> Result, JsErrorBox> { let error_callback = match error_callback { Some(cb) => Some( v8::Local::::try_from(cb) @@ -649,22 +648,16 @@ pub fn op_serialize( if let Some(shared_array_buffer_store) = &state.shared_array_buffer_store { if !buf.is_detachable() { - return Err( - JsErrorBox::type_error( - "item in transferredArrayBuffers is not transferable", - ) - .into(), - ); + return Err(JsErrorBox::type_error( + "item in transferredArrayBuffers is not transferable", + )); } if buf.was_detached() { - return Err( - JsErrorBox::new( - "DOMExceptionOperationError", - format!("ArrayBuffer at index {index} is already detached"), - ) - .into(), - ); + return Err(JsErrorBox::new( + "DOMExceptionOperationError", + format!("ArrayBuffer at index {index} is already detached"), + )); } let backing_store = buf.get_backing_store(); @@ -687,7 +680,7 @@ pub fn op_serialize( let vector = value_serializer.release(); Ok(vector) } else { - Err(JsErrorBox::type_error("Failed to serialize response").into()) + Err(JsErrorBox::type_error("Failed to serialize response")) } } @@ -698,7 +691,7 @@ pub fn op_deserialize<'a>( host_objects: Option>, transferred_array_buffers: Option>, for_storage: bool, -) -> Result, OpError> { +) -> Result, JsErrorBox> { let host_objects = match host_objects { Some(value) => Some( v8::Local::::try_from(value) @@ -727,7 +720,7 @@ pub fn op_deserialize<'a>( .read_header(scope.get_current_context()) .unwrap_or_default(); if !parsed_header { - return Err(JsErrorBox::range_error("could not deserialize value").into()); + return Err(JsErrorBox::range_error("could not deserialize value")); } if let Some(transferred_array_buffers) = transferred_array_buffers { @@ -739,12 +732,9 @@ pub fn op_deserialize<'a>( let id = match id_val.number_value(scope) { Some(id) => id as u32, None => { - return Err( - JsErrorBox::type_error( - "item in transferredArrayBuffers not number", - ) - .into(), - ) + return Err(JsErrorBox::type_error( + "item in transferredArrayBuffers not number", + )) } }; if let Some(backing_store) = shared_array_buffer_store.take(id) { @@ -755,7 +745,7 @@ pub fn op_deserialize<'a>( } else { return Err(JsErrorBox::type_error( "transferred array buffer not present in shared_array_buffer_store", - ).into()); + )); } } } @@ -764,7 +754,7 @@ pub fn op_deserialize<'a>( let value = value_deserializer.read_value(scope.get_current_context()); match value { Some(deserialized) => Ok(deserialized), - None => Err(JsErrorBox::range_error("could not deserialize value").into()), + None => Err(JsErrorBox::range_error("could not deserialize value")), } } @@ -800,16 +790,15 @@ pub fn op_set_promise_hooks( before_hook: v8::Local, after_hook: v8::Local, resolve_hook: v8::Local, -) -> Result<(), OpError> { +) -> Result<(), crate::error::DataError> { let v8_fns = [init_hook, before_hook, after_hook, resolve_hook] .into_iter() .enumerate() .filter(|(_, hook)| !hook.is_undefined()) .try_fold([None; 4], |mut v8_fns, (i, hook)| { - let v8_fn = v8::Local::::try_from(hook) - .map_err(crate::error::DataError)?; + let v8_fn = v8::Local::::try_from(hook)?; v8_fns[i] = Some(v8_fn); - Ok::<_, OpError>(v8_fns) + Ok::<_, crate::error::DataError>(v8_fns) })?; scope.set_promise_hooks( @@ -946,16 +935,15 @@ pub fn op_memory_usage(scope: &mut v8::HandleScope) -> MemoryUsage { pub fn op_set_wasm_streaming_callback( scope: &mut v8::HandleScope, #[global] cb: v8::Global, -) -> Result<(), OpError> { +) -> Result<(), JsErrorBox> { let context_state_rc = JsRealm::state_from_scope(scope); // The callback to pass to the v8 API has to be a unit type, so it can't // borrow or move any local variables. Therefore, we're storing the JS // callback in a JsRuntimeState slot. if context_state_rc.js_wasm_streaming_cb.borrow().is_some() { - return Err( - JsErrorBox::type_error("op_set_wasm_streaming_callback already called") - .into(), - ); + return Err(JsErrorBox::type_error( + "op_set_wasm_streaming_callback already called", + )); } *context_state_rc.js_wasm_streaming_cb.borrow_mut() = Some(Rc::new(cb)); @@ -994,7 +982,7 @@ pub fn op_abort_wasm_streaming( state: Rc>, rid: u32, error: v8::Local, -) -> Result<(), OpError> { +) -> Result<(), ResourceError> { // NOTE: v8::WasmStreaming::abort can't be called while `state` is borrowed; let wasm_streaming = state .borrow_mut() diff --git a/core/runtime/jsruntime.rs b/core/runtime/jsruntime.rs index ef791238d..cafbce00e 100644 --- a/core/runtime/jsruntime.rs +++ b/core/runtime/jsruntime.rs @@ -2569,6 +2569,7 @@ impl JsRuntime { .complete(RuntimeActivityType::AsyncOp, promise_id as _); dispatched_ops |= true; args.push(v8::Integer::new(scope, promise_id).into()); + args.push(v8::Boolean::new(scope, res.is_ok()).into()); args.push(res.unwrap_or_else(std::convert::identity)); } diff --git a/core/runtime/op_driver/futures_unordered_driver.rs b/core/runtime/op_driver/futures_unordered_driver.rs index a99c7ccb5..e7ca4da05 100644 --- a/core/runtime/op_driver/futures_unordered_driver.rs +++ b/core/runtime/op_driver/futures_unordered_driver.rs @@ -8,6 +8,7 @@ use super::OpInflightStats; use crate::OpId; use crate::PromiseId; use bit_set::BitSet; +use deno_error::JsErrorClass; use deno_unsync::spawn; use deno_unsync::JoinHandle; use deno_unsync::UnsyncWaker; @@ -124,7 +125,7 @@ impl FuturesUnorderedDriver { impl OpDriver for FuturesUnorderedDriver { fn submit_op_fallible< R: 'static, - E: Into + 'static, + E: JsErrorClass + 'static, const LAZY: bool, const DEFERRED: bool, >( diff --git a/core/runtime/op_driver/mod.rs b/core/runtime/op_driver/mod.rs index 37a244722..31379155f 100644 --- a/core/runtime/op_driver/mod.rs +++ b/core/runtime/op_driver/mod.rs @@ -3,6 +3,7 @@ use crate::OpId; use crate::PromiseId; use bit_set::BitSet; +use deno_error::JsErrorClass; use std::future::Future; use std::task::Context; use std::task::Poll; @@ -15,8 +16,6 @@ mod op_results; #[allow(unused)] pub use futures_unordered_driver::FuturesUnorderedDriver; -pub use self::op_results::OpError; -pub use self::op_results::OpErrorWrapper; pub use self::op_results::OpMappingContext; pub use self::op_results::OpResult; use self::op_results::PendingOpInfo; @@ -86,7 +85,7 @@ pub(crate) trait OpDriver: /// might return an error (`Result`). fn submit_op_fallible< R: 'static, - E: Into + 'static, + E: JsErrorClass + 'static, const LAZY: bool, const DEFERRED: bool, >( @@ -100,7 +99,7 @@ pub(crate) trait OpDriver: /// Submits an operation that is expected to complete successfully without errors. #[inline(always)] #[allow(clippy::too_many_arguments)] - fn submit_op_fallible_scheduling + 'static>( + fn submit_op_fallible_scheduling( &self, scheduling: OpScheduling, op_id: OpId, @@ -149,6 +148,7 @@ mod tests { use super::op_results::*; use super::*; use bit_set::BitSet; + use deno_error::JsErrorBox; use rstest::rstest; use std::future::poll_fn; @@ -160,9 +160,9 @@ mod tests { fn map_error( _context: &mut Self::Context, - err: OpError, - ) -> UnmappedResult<'s, Self> { - Ok(format!("{err:?}")) + err: JsErrorBox, + ) -> Self::Result { + format!("{err:?}") } fn map_mapping_error( diff --git a/core/runtime/op_driver/op_results.rs b/core/runtime/op_driver/op_results.rs index 6b1ae6147..97567b183 100644 --- a/core/runtime/op_driver/op_results.rs +++ b/core/runtime/op_driver/op_results.rs @@ -4,11 +4,8 @@ use super::erased_future::TypeErased; use super::future_arena::FutureContextMapper; use crate::OpId; use crate::PromiseId; +use deno_error::JsErrorBox; use deno_error::JsErrorClass; -use serde::ser::SerializeStruct; -use serde::Serialize; -use std::any::Any; -use std::borrow::Cow; const MAX_RESULT_SIZE: usize = 32; @@ -26,10 +23,7 @@ pub trait OpMappingContextLifetime<'s> { type Result: 's; type MappingError: 's; - fn map_error( - context: &mut Self::Context, - err: OpError, - ) -> UnmappedResult<'s, Self>; + fn map_error(context: &mut Self::Context, err: JsErrorBox) -> Self::Result; fn map_mapping_error( context: &mut Self::Context, err: Self::MappingError, @@ -69,16 +63,16 @@ impl<'s> OpMappingContextLifetime<'s> for V8OpMappingContext { #[inline(always)] fn map_error( scope: &mut v8::HandleScope<'s>, - err: OpError, - ) -> UnmappedResult<'s, Self> { - serde_v8::to_v8(scope, err) + err: JsErrorBox, + ) -> Self::Result { + crate::error::to_v8_error(scope, &err) } fn map_mapping_error( scope: &mut v8::HandleScope<'s>, err: Self::MappingError, ) -> v8::Local<'s, v8::Value> { - serde_v8::to_v8(scope, OpError::from(err)).unwrap() + crate::error::to_v8_error(scope, &err) } } @@ -107,14 +101,14 @@ pub struct PendingOp(pub PendingOpInfo, pub OpResult); impl PendingOp { #[inline(always)] - pub fn new + 'static>( + pub fn new( info: PendingOpInfo, rv_map: C::MappingFn, result: Result, ) -> Self { match result { Ok(r) => PendingOp(info, OpResult::new_value(r, rv_map)), - Err(err) => PendingOp(info, OpResult::Err(err.into())), + Err(err) => PendingOp(info, OpResult::Err(JsErrorBox::from_err(err))), } } @@ -150,7 +144,7 @@ impl Clone } } -impl + 'static> +impl FutureContextMapper, PendingOpInfo, Result> for PendingOpMappingInfo { @@ -226,7 +220,7 @@ impl ValueLargeFn for ValueLarge { pub enum OpResult { /// Errors. - Err(OpError), + Err(JsErrorBox), /// For small ops, we include them in an erased type container. Value(OpValue), /// For ops that return "large" results (> MAX_RESULT_SIZE bytes) we just box a function @@ -248,7 +242,7 @@ impl OpResult { context: &mut >::Context, ) -> MappedResult<'a, C> { let (success, res) = match self { - Self::Err(err) => (false, C::map_error(context, err)), + Self::Err(err) => (false, Ok(C::map_error(context, err))), Self::Value(f) => (true, (f.map_fn)(&(), context, f.rv_map, f.value)), Self::ValueLarge(f) => (true, f.unwrap(context)), }; @@ -261,61 +255,3 @@ impl OpResult { } } } - -#[derive(Debug)] -pub struct OpError(Box); - -impl std::error::Error for OpError {} - -impl std::fmt::Display for OpError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {}", self.0.get_class(), self.0.get_message()) - } -} - -impl From for OpError { - fn from(err: T) -> Self { - Self(Box::new(err)) - } -} - -impl Serialize for OpError { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut serde_state = serializer.serialize_struct("OpError", 3)?; - serde_state.serialize_field("$err_class_name", &self.0.get_class())?; - serde_state.serialize_field("message", &self.0.get_message())?; - serde_state.serialize_field( - "additional_properties", - &self.0.get_additional_properties(), - )?; - serde_state.end() - } -} - -/// Wrapper type to avoid circular trait implementation error due to From implementation -#[derive(Debug, thiserror::Error)] -#[error(transparent)] -pub struct OpErrorWrapper(pub OpError); - -impl JsErrorClass for OpErrorWrapper { - fn get_class(&self) -> Cow<'static, str> { - self.0 .0.get_class() - } - - fn get_message(&self) -> Cow<'static, str> { - self.0 .0.get_message() - } - - fn get_additional_properties( - &self, - ) -> Vec<(Cow<'static, str>, Cow<'static, str>)> { - self.0 .0.get_additional_properties() - } - - fn as_any(&self) -> &dyn Any { - self.0 .0.as_any() - } -} diff --git a/core/runtime/ops.rs b/core/runtime/ops.rs index 57f0f8a4b..79f46be94 100644 --- a/core/runtime/ops.rs +++ b/core/runtime/ops.rs @@ -4,6 +4,7 @@ use super::op_driver::OpDriver; use super::op_driver::OpScheduling; use super::op_driver::V8RetValMapper; use crate::ops::*; +use deno_error::JsErrorClass; use futures::future::Future; use serde::Deserialize; use serde_v8::from_v8; @@ -48,10 +49,7 @@ pub fn map_async_op_infallible( } #[inline(always)] -pub fn map_async_op_fallible< - R: 'static, - E: Into + 'static, ->( +pub fn map_async_op_fallible( ctx: &OpCtx, lazy: bool, deferred: bool, @@ -536,7 +534,6 @@ mod tests { use crate::convert::Number; use crate::convert::Smi; use crate::error::CoreError; - use crate::error::OpError; use crate::external; use crate::external::ExternalPointer; use crate::op2; @@ -887,27 +884,27 @@ mod tests { } #[op2(fast)] - pub fn op_test_result_void_switch() -> Result<(), OpError> { + pub fn op_test_result_void_switch() -> Result<(), JsErrorBox> { let count = RETURN_COUNT.with(|count| { let new = count.get() + 1; count.set(new); new }); if count > 5000 { - Err(JsErrorBox::generic("failed!!!").into()) + Err(JsErrorBox::generic("failed!!!")) } else { Ok(()) } } #[op2(fast)] - pub fn op_test_result_void_err() -> Result<(), OpError> { - Err(JsErrorBox::generic("failed!!!").into()) + pub fn op_test_result_void_err() -> Result<(), JsErrorBox> { + Err(JsErrorBox::generic("failed!!!")) } #[allow(clippy::unnecessary_wraps)] #[op2(fast)] - pub fn op_test_result_void_ok() -> Result<(), OpError> { + pub fn op_test_result_void_ok() -> Result<(), JsErrorBox> { Ok(()) } @@ -946,13 +943,13 @@ mod tests { } #[op2(fast)] - pub fn op_test_result_primitive_err() -> Result { - Err(JsErrorBox::generic("failed!!!").into()) + pub fn op_test_result_primitive_err() -> Result { + Err(JsErrorBox::generic("failed!!!")) } #[allow(clippy::unnecessary_wraps)] #[op2(fast)] - pub fn op_test_result_primitive_ok() -> Result { + pub fn op_test_result_primitive_ok() -> Result { Ok(123) } @@ -978,11 +975,11 @@ mod tests { } #[op2(fast)] - pub fn op_test_bool_result(b: bool) -> Result { + pub fn op_test_bool_result(b: bool) -> Result { if b { Ok(true) } else { - Err(JsErrorBox::generic("false!!!").into()) + Err(JsErrorBox::generic("false!!!")) } } @@ -1012,12 +1009,12 @@ mod tests { } #[op2(fast)] - pub fn op_test_float_result(a: f32, b: f64) -> Result { + pub fn op_test_float_result(a: f32, b: f64) -> Result { let a = a as f64; if a + b >= 0. { Ok(a + b) } else { - Err(JsErrorBox::generic("negative!!!").into()) + Err(JsErrorBox::generic("negative!!!")) } } @@ -1325,11 +1322,11 @@ mod tests { pub fn op_test_v8_type_handle_scope_result<'s>( scope: &mut v8::HandleScope<'s>, o: &v8::Object, - ) -> Result, OpError> { + ) -> Result, JsErrorBox> { let key = v8::String::new(scope, "key").unwrap().into(); o.get(scope, key) .filter(|v| !v.is_null_or_undefined()) - .ok_or(JsErrorBox::generic("error!!!").into()) + .ok_or(JsErrorBox::generic("error!!!")) } #[tokio::test] @@ -2176,9 +2173,9 @@ mod tests { } #[op2(async)] - pub async fn op_async_sleep_error() -> Result<(), OpError> { + pub async fn op_async_sleep_error() -> Result<(), JsErrorBox> { tokio::time::sleep(Duration::from_millis(500)).await; - Err(JsErrorBox::generic("whoops").into()) + Err(JsErrorBox::generic("whoops")) } #[tokio::test] @@ -2194,13 +2191,13 @@ mod tests { } #[op2(async(deferred), fast)] - pub async fn op_async_deferred_success() -> Result { + pub async fn op_async_deferred_success() -> Result { Ok(42) } #[op2(async(deferred), fast)] - pub async fn op_async_deferred_error() -> Result<(), OpError> { - Err(JsErrorBox::generic("whoops").into()) + pub async fn op_async_deferred_error() -> Result<(), JsErrorBox> { + Err(JsErrorBox::generic("whoops")) } #[tokio::test] @@ -2222,13 +2219,13 @@ mod tests { } #[op2(async(lazy), fast)] - pub async fn op_async_lazy_success() -> Result { + pub async fn op_async_lazy_success() -> Result { Ok(42) } #[op2(async(lazy), fast)] - pub async fn op_async_lazy_error() -> Result<(), OpError> { - Err(JsErrorBox::generic("whoops").into()) + pub async fn op_async_lazy_error() -> Result<(), JsErrorBox> { + Err(JsErrorBox::generic("whoops")) } #[tokio::test] @@ -2253,17 +2250,17 @@ mod tests { #[op2(async)] pub fn op_async_result_impl( mode: u8, - ) -> Result>, OpError> { + ) -> Result>, JsErrorBox> { if mode == 0 { - return Err(JsErrorBox::generic("early exit").into()); + return Err(JsErrorBox::generic("early exit")); } Ok(async move { if mode == 1 { - return Err(JsErrorBox::generic("early async exit").into()); + return Err(JsErrorBox::generic("early async exit")); } tokio::time::sleep(Duration::from_millis(500)).await; if mode == 2 { - return Err(JsErrorBox::generic("late async exit").into()); + return Err(JsErrorBox::generic("late async exit")); } Ok(()) }) @@ -2377,7 +2374,7 @@ mod tests { #[serde] pub async fn op_async_serde_option_v8( #[serde] mut serde: Serde, - ) -> Result, OpError> { + ) -> Result, JsErrorBox> { serde.s += "!"; Ok(Some(serde)) } diff --git a/core/runtime/tests/error.rs b/core/runtime/tests/error.rs index a29ccfd6b..8a9bab739 100644 --- a/core/runtime/tests/error.rs +++ b/core/runtime/tests/error.rs @@ -1,7 +1,6 @@ // Copyright 2018-2025 the Deno authors. MIT license. use crate::error::CoreError; -use crate::error::OpError; use crate::op2; use crate::JsRuntime; use crate::RuntimeOptions; @@ -12,8 +11,8 @@ use std::task::Poll; #[tokio::test] async fn test_error_builder() { #[op2(fast)] - fn op_err() -> Result<(), OpError> { - Err(JsErrorBox::new("DOMExceptionOperationError", "abc").into()) + fn op_err() -> Result<(), JsErrorBox> { + Err(JsErrorBox::new("DOMExceptionOperationError", "abc")) } deno_core::extension!(test_ext, ops = [op_err]); diff --git a/core/runtime/tests/misc.rs b/core/runtime/tests/misc.rs index 7185a1a8f..312b1359c 100644 --- a/core/runtime/tests/misc.rs +++ b/core/runtime/tests/misc.rs @@ -1,7 +1,6 @@ // Copyright 2018-2025 the Deno authors. MIT license. use crate::error::CoreError; -use crate::error::OpError; use crate::modules::StaticModuleLoader; use crate::runtime::tests::setup; use crate::runtime::tests::Mode; @@ -9,6 +8,7 @@ use crate::*; use cooked_waker::IntoWaker; use cooked_waker::Wake; use cooked_waker::WakeRef; +use deno_error::JsErrorBox; use futures::future::poll_fn; use parking_lot::Mutex; use rstest::rstest; @@ -86,7 +86,7 @@ async fn test_wakers_for_async_ops() { static STATE: AtomicI8 = AtomicI8::new(0); #[op2(async)] - async fn op_async_sleep() -> Result<(), OpError> { + async fn op_async_sleep() -> Result<(), JsErrorBox> { STATE.store(1, Ordering::SeqCst); tokio::time::sleep(std::time::Duration::from_millis(1)).await; STATE.store(2, Ordering::SeqCst); @@ -658,7 +658,7 @@ fn test_is_proxy() { #[tokio::test] async fn test_set_macrotask_callback_set_next_tick_callback() { #[op2(async)] - async fn op_async_sleep() -> Result<(), OpError> { + async fn op_async_sleep() -> Result<(), JsErrorBox> { // Future must be Poll::Pending on first call tokio::time::sleep(std::time::Duration::from_millis(1)).await; Ok(()) @@ -709,14 +709,14 @@ fn test_has_tick_scheduled() { #[allow(clippy::unnecessary_wraps)] #[op2(fast)] - fn op_macrotask() -> Result<(), OpError> { + fn op_macrotask() -> Result<(), JsErrorBox> { MACROTASK.fetch_add(1, Ordering::Relaxed); Ok(()) } #[allow(clippy::unnecessary_wraps)] #[op2(fast)] - fn op_next_tick() -> Result<(), OpError> { + fn op_next_tick() -> Result<(), JsErrorBox> { NEXT_TICK.fetch_add(1, Ordering::Relaxed); Ok(()) } @@ -980,9 +980,9 @@ async fn test_stalled_tla() { #[tokio::test] async fn test_dynamic_import_module_error_stack() { #[op2(async)] - async fn op_async_error() -> Result<(), OpError> { + async fn op_async_error() -> Result<(), JsErrorBox> { tokio::time::sleep(std::time::Duration::from_millis(1)).await; - Err(deno_error::JsErrorBox::type_error("foo").into()) + Err(deno_error::JsErrorBox::type_error("foo")) } deno_core::extension!(test_ext, ops = [op_async_error]); let loader = StaticModuleLoader::new([ @@ -1204,7 +1204,7 @@ async fn task_spawner_cross_thread_blocking() { #[tokio::test] async fn terminate_execution_run_event_loop_js() { #[op2(async)] - async fn op_async_sleep() -> Result<(), OpError> { + async fn op_async_sleep() -> Result<(), JsErrorBox> { tokio::time::sleep(std::time::Duration::from_millis(100)).await; Ok(()) } diff --git a/core/runtime/tests/mod.rs b/core/runtime/tests/mod.rs index 65397adee..5d6538fac 100644 --- a/core/runtime/tests/mod.rs +++ b/core/runtime/tests/mod.rs @@ -1,11 +1,11 @@ // Copyright 2018-2025 the Deno authors. MIT license. -use crate::error::OpError; use crate::op2; use crate::CrossIsolateStore; use crate::JsRuntime; use crate::OpState; use crate::RuntimeOptions; +use deno_error::JsErrorBox; use serde_v8::JsBuffer; use std::cell::RefCell; use std::rc::Rc; @@ -37,7 +37,7 @@ async fn op_test( rc_op_state: Rc>, control: u8, #[buffer] buf: Option, -) -> Result { +) -> Result { let op_state_ = rc_op_state.borrow(); let test_state = op_state_.borrow::(); test_state.dispatch_count.fetch_add(1, Ordering::Relaxed); diff --git a/core/runtime/tests/ops.rs b/core/runtime/tests/ops.rs index 70ad86308..4429d3ecb 100644 --- a/core/runtime/tests/ops.rs +++ b/core/runtime/tests/ops.rs @@ -2,7 +2,6 @@ #![allow(clippy::print_stdout, clippy::print_stderr, clippy::unused_async)] -use crate::error::OpError; use crate::extensions::OpDecl; use crate::modules::StaticModuleLoader; use crate::runtime::tests::setup; @@ -24,7 +23,7 @@ async fn test_async_opstate_borrow() { #[op2(async)] async fn op_async_borrow( op_state: Rc>, - ) -> Result<(), OpError> { + ) -> Result<(), JsErrorBox> { let n = { let op_state = op_state.borrow(); let inner_state = op_state.borrow::(); @@ -63,7 +62,7 @@ async fn test_sync_op_serialize_object_with_numbers_as_keys() { #[op2] fn op_sync_serialize_object_with_numbers_as_keys( #[serde] value: serde_json::Value, - ) -> Result<(), OpError> { + ) -> Result<(), JsErrorBox> { assert_eq!( value.to_string(), r#"{"lines":{"100":{"unit":"m"},"200":{"unit":"cm"}}}"# @@ -105,7 +104,7 @@ async fn test_async_op_serialize_object_with_numbers_as_keys() { #[op2(async)] async fn op_async_serialize_object_with_numbers_as_keys( #[serde] value: serde_json::Value, - ) -> Result<(), OpError> { + ) -> Result<(), JsErrorBox> { assert_eq!( value.to_string(), r#"{"lines":{"100":{"unit":"m"},"200":{"unit":"cm"}}}"# @@ -148,7 +147,7 @@ fn test_op_return_serde_v8_error() { #[allow(clippy::unnecessary_wraps)] #[op2] #[serde] - fn op_err() -> Result, OpError> { + fn op_err() -> Result, JsErrorBox> { Ok([(1, 2), (3, 4)].into_iter().collect()) // Maps can't have non-string keys in serde_v8 } @@ -175,7 +174,7 @@ fn test_op_high_arity() { #[number] x2: i64, #[number] x3: i64, #[number] x4: i64, - ) -> Result { + ) -> Result { Ok(x1 + x2 + x3 + x4) } @@ -196,7 +195,7 @@ fn test_op_disabled() { #[allow(clippy::unnecessary_wraps)] #[op2(fast)] #[number] - fn op_foo() -> Result { + fn op_foo() -> Result { Ok(42) } @@ -220,14 +219,16 @@ fn test_op_disabled() { fn test_op_detached_buffer() { #[allow(clippy::unnecessary_wraps)] #[op2] - fn op_sum_take(#[buffer(detach)] b: JsBuffer) -> Result { + fn op_sum_take(#[buffer(detach)] b: JsBuffer) -> Result { Ok(b.as_ref().iter().clone().map(|x| *x as u32).sum()) } #[allow(clippy::unnecessary_wraps)] #[op2] #[buffer] - fn op_boomerang(#[buffer(detach)] b: JsBuffer) -> Result { + fn op_boomerang( + #[buffer(detach)] b: JsBuffer, + ) -> Result { Ok(b) } @@ -302,14 +303,14 @@ fn duplicate_op_names() { #[allow(clippy::unnecessary_wraps)] #[op2] #[string] - pub fn op_test() -> Result { + pub fn op_test() -> Result { Ok(String::from("Test")) } } #[op2] #[string] - pub fn op_test() -> Result { + pub fn op_test() -> Result { Ok(String::from("Test")) } @@ -325,13 +326,13 @@ fn ops_in_js_have_proper_names() { #[allow(clippy::unnecessary_wraps)] #[op2] #[string] - fn op_test_sync() -> Result { + fn op_test_sync() -> Result { Ok(String::from("Test")) } #[op2(async)] #[string] - async fn op_test_async() -> Result { + async fn op_test_async() -> Result { Ok(String::from("Test")) } @@ -540,9 +541,9 @@ pub async fn op_async() { #[op2(async)] #[allow(unreachable_code)] -pub fn op_async_impl_future_error() -> Result, OpError> -{ - return Err(JsErrorBox::generic("dead").into()); +pub fn op_async_impl_future_error( +) -> Result, JsErrorBox> { + return Err(JsErrorBox::generic("dead")); Ok(async {}) } @@ -553,16 +554,16 @@ pub async fn op_async_yield() { } #[op2(async)] -pub async fn op_async_yield_error() -> Result<(), OpError> { +pub async fn op_async_yield_error() -> Result<(), JsErrorBox> { tokio::task::yield_now().await; println!("op_async_yield_error!"); - Err(JsErrorBox::generic("dead").into()) + Err(JsErrorBox::generic("dead")) } #[op2(async)] -pub async fn op_async_error() -> Result<(), OpError> { +pub async fn op_async_error() -> Result<(), JsErrorBox> { println!("op_async_error!"); - Err(JsErrorBox::generic("dead").into()) + Err(JsErrorBox::generic("dead")) } #[op2(async(deferred), fast)] @@ -581,8 +582,8 @@ pub fn op_sync() { } #[op2(fast)] -pub fn op_sync_error() -> Result<(), OpError> { - Err(JsErrorBox::generic("Always fails").into()) +pub fn op_sync_error() -> Result<(), JsErrorBox> { + Err(JsErrorBox::generic("Always fails")) } #[op2(fast)] diff --git a/core/runtime/tests/snapshot.rs b/core/runtime/tests/snapshot.rs index 5843e4f7e..3195d360a 100644 --- a/core/runtime/tests/snapshot.rs +++ b/core/runtime/tests/snapshot.rs @@ -2,11 +2,11 @@ use self::runtime::create_snapshot; use self::runtime::CreateSnapshotOptions; -use crate::error::OpError; use crate::modules::ModuleInfo; use crate::modules::RequestedModuleType; use crate::runtime::NO_OF_BUILTIN_MODULES; use crate::*; +use deno_error::JsErrorBox; use std::borrow::Cow; use std::cell::RefCell; use std::rc::Rc; @@ -234,7 +234,7 @@ fn es_snapshot() { #[allow(clippy::unnecessary_wraps)] #[op2] #[string] - fn op_test() -> Result { + fn op_test() -> Result { Ok(String::from("test")) } let mut runtime = JsRuntimeForSnapshot::new(RuntimeOptions { diff --git a/ops/compile_test_runner/Cargo.toml b/ops/compile_test_runner/Cargo.toml index 2518ac07c..422b6a250 100644 --- a/ops/compile_test_runner/Cargo.toml +++ b/ops/compile_test_runner/Cargo.toml @@ -15,6 +15,7 @@ description = "Compile-test runner for deno_ops" [dev-dependencies] bytes.workspace = true deno_core.workspace = true +deno_error.workspace = true deno_ops.workspace = true pretty_assertions.workspace = true prettyplease = "0.2.9" diff --git a/ops/op2/dispatch_fast.rs b/ops/op2/dispatch_fast.rs index 322005243..95d1da516 100644 --- a/ops/op2/dispatch_fast.rs +++ b/ops/op2/dispatch_fast.rs @@ -352,7 +352,7 @@ pub(crate) fn generate_fast_result_early_exit( let mut scope = #create_scope; let exception = deno_core::error::to_v8_error( &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), + &err, ); scope.throw_exception(exception); // SAFETY: All fast return types have zero as a valid value diff --git a/ops/op2/dispatch_slow.rs b/ops/op2/dispatch_slow.rs index 253cd2bf6..130d380c3 100644 --- a/ops/op2/dispatch_slow.rs +++ b/ops/op2/dispatch_slow.rs @@ -1178,7 +1178,7 @@ pub(crate) fn throw_exception( #maybe_opctx let exception = deno_core::error::to_v8_error( &mut #scope, - &deno_core::error::OpErrorWrapper(err.into()), + &err, ); #scope.throw_exception(exception); return 1; diff --git a/ops/op2/signature.rs b/ops/op2/signature.rs index 733bc9be4..007a7a634 100644 --- a/ops/op2/signature.rs +++ b/ops/op2/signature.rs @@ -1967,19 +1967,19 @@ mod tests { (Numeric(__SMI__, None)) -> Result(Numeric(__SMI__, None)) ); test!( - fn op_option_numeric_result(state: &mut OpState) -> Result, OpError>; + fn op_option_numeric_result(state: &mut OpState) -> Result, JsErrorBox>; (Ref(Mut, OpState)) -> Result(OptionNumeric(u32, None)) ); test!( - #[smi] fn op_option_numeric_smi_result(#[smi] a: Option) -> Result, OpError>; + #[smi] fn op_option_numeric_smi_result(#[smi] a: Option) -> Result, JsErrorBox>; (OptionNumeric(__SMI__, None)) -> Result(OptionNumeric(__SMI__, None)) ); test!( - fn op_ffi_read_f64(state: &mut OpState, ptr: *mut c_void, #[bigint] offset: isize) -> Result; + fn op_ffi_read_f64(state: &mut OpState, ptr: *mut c_void, #[bigint] offset: isize) -> Result; (Ref(Mut, OpState), External(Ptr(Mut)), Numeric(isize, None)) -> Result(Numeric(f64, None)) ); test!( - #[number] fn op_64_bit_number(#[number] offset: isize) -> Result; + #[number] fn op_64_bit_number(#[number] offset: isize) -> Result; (Numeric(isize, Number)) -> Result(Numeric(u64, Number)) ); test!( @@ -2080,7 +2080,7 @@ mod tests { #[smi] rid: ResourceId ) -> Result< ExtremelyLongTypeNameThatForcesEverythingToWrapAndAddsCommas, - OpError, + JsErrorBox, >; (RcRefCell(OpState), Numeric(__SMI__, None)) -> FutureResult(SerdeV8(ExtremelyLongTypeNameThatForcesEverythingToWrapAndAddsCommas)) ); diff --git a/ops/op2/test_cases/async/async_arg_return_result.out b/ops/op2/test_cases/async/async_arg_return_result.out index 508491d8a..c740879d4 100644 --- a/ops/op2/test_cases/async/async_arg_return_result.out +++ b/ops/op2/test_cases/async/async_arg_return_result.out @@ -71,10 +71,7 @@ pub const fn op_async() -> ::deno_core::_ops::OpDecl { let mut scope = unsafe { deno_core::v8::CallbackScope::new(info) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return 1; } diff --git a/ops/op2/test_cases/async/async_opstate.out b/ops/op2/test_cases/async/async_opstate.out index 4747d8992..f7f10d7be 100644 --- a/ops/op2/test_cases/async/async_opstate.out +++ b/ops/op2/test_cases/async/async_opstate.out @@ -67,10 +67,7 @@ pub const fn op_async_opstate() -> ::deno_core::_ops::OpDecl { let mut scope = unsafe { deno_core::v8::CallbackScope::new(info) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return 1; } diff --git a/ops/op2/test_cases/async/async_result.out b/ops/op2/test_cases/async/async_result.out index 0b0c077f9..9d461ab99 100644 --- a/ops/op2/test_cases/async/async_result.out +++ b/ops/op2/test_cases/async/async_result.out @@ -63,10 +63,7 @@ pub const fn op_async() -> ::deno_core::_ops::OpDecl { let mut scope = unsafe { deno_core::v8::CallbackScope::new(info) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return 1; } diff --git a/ops/op2/test_cases/async/async_result_impl.out b/ops/op2/test_cases/async/async_result_impl.out index 2d87cbc77..bb186cb4c 100644 --- a/ops/op2/test_cases/async/async_result_impl.out +++ b/ops/op2/test_cases/async/async_result_impl.out @@ -57,10 +57,7 @@ pub const fn op_async_result_impl() -> ::deno_core::_ops::OpDecl { Ok(result) => result, Err(err) => { let mut scope = unsafe { deno_core::v8::CallbackScope::new(info) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return 1; } @@ -83,10 +80,7 @@ pub const fn op_async_result_impl() -> ::deno_core::_ops::OpDecl { let mut scope = unsafe { deno_core::v8::CallbackScope::new(info) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return 1; } @@ -134,7 +128,7 @@ pub const fn op_async_result_impl() -> ::deno_core::_ops::OpDecl { #[allow(clippy::too_many_arguments)] pub fn call( x: i32, - ) -> Result>, OpError> { + ) -> Result>, JsErrorBox> { Ok(async move { Ok(x) }) } } diff --git a/ops/op2/test_cases/async/async_result_impl.rs b/ops/op2/test_cases/async/async_result_impl.rs index fe45ccd2f..e0fd51c86 100644 --- a/ops/op2/test_cases/async/async_result_impl.rs +++ b/ops/op2/test_cases/async/async_result_impl.rs @@ -3,12 +3,12 @@ #![deny(warnings)] deno_ops_compile_test_runner::prelude!(); -use deno_core::error::OpError; +use deno_error::JsErrorBox; use std::future::Future; #[op2(async)] pub fn op_async_result_impl( x: i32, -) -> Result>, OpError> { +) -> Result>, JsErrorBox> { Ok(async move { Ok(x) }) } diff --git a/ops/op2/test_cases/async/async_result_smi.out b/ops/op2/test_cases/async/async_result_smi.out index 05aad1f6c..8daeb1395 100644 --- a/ops/op2/test_cases/async/async_result_smi.out +++ b/ops/op2/test_cases/async/async_result_smi.out @@ -87,10 +87,7 @@ pub const fn op_async() -> ::deno_core::_ops::OpDecl { let mut scope = unsafe { deno_core::v8::CallbackScope::new(info) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return 1; } diff --git a/ops/op2/test_cases/compiler_pass/async.rs b/ops/op2/test_cases/compiler_pass/async.rs index 3b8774da4..f7669015e 100644 --- a/ops/op2/test_cases/compiler_pass/async.rs +++ b/ops/op2/test_cases/compiler_pass/async.rs @@ -3,9 +3,9 @@ #![deny(warnings)] deno_ops_compile_test_runner::prelude!(); -use deno_core::error::OpError; use deno_core::JsBuffer; use deno_core::OpState; +use deno_error::JsErrorBox; use std::cell::RefCell; use std::future::Future; use std::rc::Rc; @@ -26,14 +26,14 @@ pub async fn op_async3(x: i32) -> std::io::Result { } #[op2(async)] -pub fn op_async4(x: i32) -> Result, OpError> { +pub fn op_async4(x: i32) -> Result, JsErrorBox> { Ok(async move { x }) } #[op2(async)] pub fn op_async5( x: i32, -) -> Result>, OpError> { +) -> Result>, JsErrorBox> { Ok(async move { Ok(x) }) } diff --git a/ops/op2/test_cases/sync/bool_result.out b/ops/op2/test_cases/sync/bool_result.out index 97006027c..8275be550 100644 --- a/ops/op2/test_cases/sync/bool_result.out +++ b/ops/op2/test_cases/sync/bool_result.out @@ -116,10 +116,7 @@ pub const fn op_bool() -> ::deno_core::_ops::OpDecl { let mut scope = unsafe { deno_core::v8::CallbackScope::new(&*fast_api_callback_options) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return unsafe { std::mem::zeroed() }; } @@ -152,10 +149,7 @@ pub const fn op_bool() -> ::deno_core::_ops::OpDecl { >::cast_unchecked(args.data()) .value() as *const deno_core::_ops::OpCtx) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return 1; } @@ -199,7 +193,7 @@ pub const fn op_bool() -> ::deno_core::_ops::OpDecl { } impl op_bool { #[allow(clippy::too_many_arguments)] - pub fn call(arg: bool) -> Result { + pub fn call(arg: bool) -> Result { Ok(arg) } } diff --git a/ops/op2/test_cases/sync/bool_result.rs b/ops/op2/test_cases/sync/bool_result.rs index da2221cb2..b97f3dc0f 100644 --- a/ops/op2/test_cases/sync/bool_result.rs +++ b/ops/op2/test_cases/sync/bool_result.rs @@ -3,9 +3,9 @@ #![deny(warnings)] deno_ops_compile_test_runner::prelude!(); -use deno_core::error::OpError; +use deno_error::JsErrorBox; #[op2(fast)] -pub fn op_bool(arg: bool) -> Result { +pub fn op_bool(arg: bool) -> Result { Ok(arg) } diff --git a/ops/op2/test_cases/sync/result_external.out b/ops/op2/test_cases/sync/result_external.out index 578d5f149..2772d9480 100644 --- a/ops/op2/test_cases/sync/result_external.out +++ b/ops/op2/test_cases/sync/result_external.out @@ -103,10 +103,7 @@ pub const fn op_external_with_result() -> ::deno_core::_ops::OpDecl { let mut scope = unsafe { deno_core::v8::CallbackScope::new(&*fast_api_callback_options) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return unsafe { std::mem::zeroed() }; } @@ -137,10 +134,7 @@ pub const fn op_external_with_result() -> ::deno_core::_ops::OpDecl { >::cast_unchecked(args.data()) .value() as *const deno_core::_ops::OpCtx) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return 1; } @@ -184,7 +178,7 @@ pub const fn op_external_with_result() -> ::deno_core::_ops::OpDecl { } impl op_external_with_result { #[allow(clippy::too_many_arguments)] - pub fn call() -> Result<*mut std::ffi::c_void, OpError> { + pub fn call() -> Result<*mut std::ffi::c_void, JsErrorBox> { Ok(0 as _) } } diff --git a/ops/op2/test_cases/sync/result_external.rs b/ops/op2/test_cases/sync/result_external.rs index e108ad647..67f8f8439 100644 --- a/ops/op2/test_cases/sync/result_external.rs +++ b/ops/op2/test_cases/sync/result_external.rs @@ -3,9 +3,9 @@ #![deny(warnings)] deno_ops_compile_test_runner::prelude!(); -use deno_core::error::OpError; +use deno_error::JsErrorBox; #[op2(fast)] -pub fn op_external_with_result() -> Result<*mut std::ffi::c_void, OpError> { +pub fn op_external_with_result() -> Result<*mut std::ffi::c_void, JsErrorBox> { Ok(0 as _) } diff --git a/ops/op2/test_cases/sync/result_primitive.out b/ops/op2/test_cases/sync/result_primitive.out index 8153b20b8..9819a3efb 100644 --- a/ops/op2/test_cases/sync/result_primitive.out +++ b/ops/op2/test_cases/sync/result_primitive.out @@ -111,10 +111,7 @@ pub const fn op_u32_with_result() -> ::deno_core::_ops::OpDecl { let mut scope = unsafe { deno_core::v8::CallbackScope::new(&*fast_api_callback_options) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return unsafe { std::mem::zeroed() }; } @@ -143,10 +140,7 @@ pub const fn op_u32_with_result() -> ::deno_core::_ops::OpDecl { >::cast_unchecked(args.data()) .value() as *const deno_core::_ops::OpCtx) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return 1; } @@ -190,7 +184,7 @@ pub const fn op_u32_with_result() -> ::deno_core::_ops::OpDecl { } impl op_u32_with_result { #[allow(clippy::too_many_arguments)] - pub fn call() -> Result { + pub fn call() -> Result { Ok(0) } } diff --git a/ops/op2/test_cases/sync/result_primitive.rs b/ops/op2/test_cases/sync/result_primitive.rs index 934c8fa25..41fd5a9f6 100644 --- a/ops/op2/test_cases/sync/result_primitive.rs +++ b/ops/op2/test_cases/sync/result_primitive.rs @@ -3,9 +3,9 @@ #![deny(warnings)] deno_ops_compile_test_runner::prelude!(); -use deno_core::error::OpError; +use deno_error::JsErrorBox; #[op2(fast)] -pub fn op_u32_with_result() -> Result { +pub fn op_u32_with_result() -> Result { Ok(0) } diff --git a/ops/op2/test_cases/sync/result_scope.out b/ops/op2/test_cases/sync/result_scope.out index 1ef0e8cc6..438810b14 100644 --- a/ops/op2/test_cases/sync/result_scope.out +++ b/ops/op2/test_cases/sync/result_scope.out @@ -109,10 +109,7 @@ pub const fn op_void_with_result() -> ::deno_core::_ops::OpDecl { let mut scope = unsafe { deno_core::v8::CallbackScope::new(&*fast_api_callback_options) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return unsafe { std::mem::zeroed() }; } @@ -144,10 +141,7 @@ pub const fn op_void_with_result() -> ::deno_core::_ops::OpDecl { >::cast_unchecked(args.data()) .value() as *const deno_core::_ops::OpCtx) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return 1; } @@ -191,7 +185,7 @@ pub const fn op_void_with_result() -> ::deno_core::_ops::OpDecl { } impl op_void_with_result { #[allow(clippy::too_many_arguments)] - pub fn call(_scope: &mut v8::HandleScope) -> Result<(), OpError> { + pub fn call(_scope: &mut v8::HandleScope) -> Result<(), JsErrorBox> { Ok(()) } } diff --git a/ops/op2/test_cases/sync/result_scope.rs b/ops/op2/test_cases/sync/result_scope.rs index f72ed1a1c..f6975cfbd 100644 --- a/ops/op2/test_cases/sync/result_scope.rs +++ b/ops/op2/test_cases/sync/result_scope.rs @@ -3,12 +3,12 @@ #![deny(warnings)] deno_ops_compile_test_runner::prelude!(); -use deno_core::error::OpError; use deno_core::v8; +use deno_error::JsErrorBox; #[op2(fast)] pub fn op_void_with_result( _scope: &mut v8::HandleScope, -) -> Result<(), OpError> { +) -> Result<(), JsErrorBox> { Ok(()) } diff --git a/ops/op2/test_cases/sync/result_void.out b/ops/op2/test_cases/sync/result_void.out index 258631c29..8b056a3eb 100644 --- a/ops/op2/test_cases/sync/result_void.out +++ b/ops/op2/test_cases/sync/result_void.out @@ -103,10 +103,7 @@ pub const fn op_void_with_result() -> ::deno_core::_ops::OpDecl { let mut scope = unsafe { deno_core::v8::CallbackScope::new(&*fast_api_callback_options) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return unsafe { std::mem::zeroed() }; } @@ -135,10 +132,7 @@ pub const fn op_void_with_result() -> ::deno_core::_ops::OpDecl { >::cast_unchecked(args.data()) .value() as *const deno_core::_ops::OpCtx) }; - let exception = deno_core::error::to_v8_error( - &mut scope, - &deno_core::error::OpErrorWrapper(err.into()), - ); + let exception = deno_core::error::to_v8_error(&mut scope, &err); scope.throw_exception(exception); return 1; } diff --git a/testing/checkin/runner/ops.rs b/testing/checkin/runner/ops.rs index 944fdecae..528257dac 100644 --- a/testing/checkin/runner/ops.rs +++ b/testing/checkin/runner/ops.rs @@ -3,7 +3,6 @@ use std::cell::RefCell; use std::rc::Rc; -use deno_core::error::OpError; use deno_core::op2; use deno_core::stats::RuntimeActivityDiff; use deno_core::stats::RuntimeActivitySnapshot; @@ -98,7 +97,7 @@ impl TestObjectWrap { fn with_rename(&self) {} #[async_method] - async fn with_async_fn(&self, #[smi] ms: u32) -> Result<(), OpError> { + async fn with_async_fn(&self, #[smi] ms: u32) -> Result<(), JsErrorBox> { tokio::time::sleep(std::time::Duration::from_millis(ms as u64)).await; Ok(()) } diff --git a/testing/checkin/runner/ops_io.rs b/testing/checkin/runner/ops_io.rs index eda5d84f0..bb02fda67 100644 --- a/testing/checkin/runner/ops_io.rs +++ b/testing/checkin/runner/ops_io.rs @@ -1,6 +1,5 @@ // Copyright 2018-2025 the Deno authors. MIT license. -use deno_core::error::OpError; use deno_core::op2; use deno_core::AsyncRefCell; use deno_core::BufView; @@ -94,7 +93,7 @@ impl Resource for FileResource { pub async fn op_file_open( #[string] path: String, op_state: Rc>, -) -> Result { +) -> Result { let tokio_file = tokio::fs::OpenOptions::new() .read(true) .write(false) @@ -110,7 +109,7 @@ pub async fn op_file_open( #[op2] #[string] -pub fn op_path_to_url(#[string] path: &str) -> Result { +pub fn op_path_to_url(#[string] path: &str) -> Result { let path = std::path::absolute(path)?; let url = url::Url::from_file_path(path).unwrap(); Ok(url.to_string()) diff --git a/testing/checkin/runner/ops_worker.rs b/testing/checkin/runner/ops_worker.rs index 160699543..0bab4f431 100644 --- a/testing/checkin/runner/ops_worker.rs +++ b/testing/checkin/runner/ops_worker.rs @@ -4,7 +4,6 @@ use super::create_runtime; use super::run_async; use super::Output; use anyhow::anyhow; -use deno_core::error::OpError; use deno_core::op2; use deno_core::url::Url; use deno_core::v8::IsolateHandle; @@ -95,7 +94,7 @@ pub fn op_worker_spawn( #[state] output: &Output, #[string] base_url: String, #[string] main_script: String, -) -> Result { +) -> Result { let output = output.clone(); let close_watcher = this_worker.close_watcher.clone(); let (init_send, init_recv) = channel(); @@ -160,7 +159,7 @@ async fn run_worker_task( pub fn op_worker_send( #[cppgc] worker: &WorkerControl, #[string] message: String, -) -> Result<(), OpError> { +) -> Result<(), tokio::sync::mpsc::error::SendError> { worker.worker_channel.tx.send(message)?; Ok(()) } @@ -175,14 +174,14 @@ pub async fn op_worker_recv(#[cppgc] worker: &WorkerControl) -> Option { #[cppgc] pub fn op_worker_parent( state: Rc>, -) -> Result { +) -> Result { let state = state.borrow_mut(); let worker: &Worker = state.borrow(); let (Some(worker_channel), Some(close_watcher)) = ( worker.parent_channel.lock().unwrap().take(), worker.parent_close_watcher.lock().unwrap().take(), ) else { - return Err(JsErrorBox::generic("No parent worker is available").into()); + return Err(JsErrorBox::generic("No parent worker is available")); }; Ok(WorkerControl { worker_channel,