diff options
-rw-r--r-- | cli/tests/integration/run_tests.rs | 7 | ||||
-rw-r--r-- | cli/tests/testdata/dom_exception_formatting.ts | 1 | ||||
-rw-r--r-- | cli/tests/testdata/dom_exception_formatting.ts.out | 2 | ||||
-rw-r--r-- | core/error.rs | 33 |
4 files changed, 42 insertions, 1 deletions
diff --git a/cli/tests/integration/run_tests.rs b/cli/tests/integration/run_tests.rs index 2c0a16582..4fd825507 100644 --- a/cli/tests/integration/run_tests.rs +++ b/cli/tests/integration/run_tests.rs @@ -1805,3 +1805,10 @@ itest!(byte_order_mark { args: "run --no-check byte_order_mark.ts", output: "byte_order_mark.out", }); + +// Regression test for https://github.com/denoland/deno/issues/11451. +itest!(dom_exception_formatting { + args: "run dom_exception_formatting.ts", + output: "dom_exception_formatting.ts.out", + exit_code: 1, +}); diff --git a/cli/tests/testdata/dom_exception_formatting.ts b/cli/tests/testdata/dom_exception_formatting.ts new file mode 100644 index 000000000..0209ec81e --- /dev/null +++ b/cli/tests/testdata/dom_exception_formatting.ts @@ -0,0 +1 @@ +throw new DOMException("foo", "SyntaxError"); diff --git a/cli/tests/testdata/dom_exception_formatting.ts.out b/cli/tests/testdata/dom_exception_formatting.ts.out new file mode 100644 index 000000000..2a815eac1 --- /dev/null +++ b/cli/tests/testdata/dom_exception_formatting.ts.out @@ -0,0 +1,2 @@ +[WILDCARD]error: Uncaught SyntaxError: foo +[WILDCARD] diff --git a/core/error.rs b/core/error.rs index abe707795..087b27c41 100644 --- a/core/error.rs +++ b/core/error.rs @@ -189,7 +189,7 @@ impl JsError { let msg = v8::Exception::create_message(scope, exception); - let (message, frames, stack) = if exception.is_native_error() { + let (message, frames, stack) = if is_instance_of_error(scope, exception) { // The exception is a JS Error object. let exception: v8::Local<v8::Object> = exception.try_into().unwrap(); @@ -296,6 +296,37 @@ pub(crate) fn attach_handle_to_error( ErrWithV8Handle::new(scope, err, handle).into() } +/// Implements `value instanceof primordials.Error` in JS. Similar to +/// `Value::is_native_error()` but more closely matches the semantics +/// of `instanceof`. `Value::is_native_error()` also checks for static class +/// inheritance rather than just scanning the prototype chain, which doesn't +/// work with our WebIDL implementation of `DOMException`. +fn is_instance_of_error<'s>( + scope: &mut v8::HandleScope<'s>, + value: v8::Local<v8::Value>, +) -> bool { + if !value.is_object() { + return false; + } + let message = v8::String::empty(scope); + let error_prototype = v8::Exception::error(scope, message) + .to_object(scope) + .unwrap() + .get_prototype(scope) + .unwrap(); + let mut maybe_prototype = + value.to_object(scope).unwrap().get_prototype(scope); + while let Some(prototype) = maybe_prototype { + if prototype.strict_equals(error_prototype) { + return true; + } + maybe_prototype = prototype + .to_object(scope) + .and_then(|o| o.get_prototype(scope)); + } + false +} + // TODO(piscisaureus): rusty_v8 should implement the Error trait on // values of type v8::Global<T>. pub(crate) struct ErrWithV8Handle { |