diff --git a/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h b/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h index 94d5bf62f1..eb089070af 100644 --- a/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h +++ b/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h @@ -24,7 +24,10 @@ template ALWAYS_INLINE bool throw_dom_exception(JS::VM& vm, JS::GlobalObject& global_object, DOM::ExceptionOr& result) { if (result.is_exception()) { - vm.throw_exception(global_object, DOMExceptionWrapper::create(global_object, const_cast(result.exception()))); + result.materialized_exception(global_object) + .visit( + [&](NonnullRefPtr dom_exception) { vm.throw_exception(global_object, DOMExceptionWrapper::create(global_object, move(dom_exception))); }, + [&](auto* js_exception) { vm.throw_exception(global_object, js_exception); }); return true; } return false; @@ -47,6 +50,11 @@ struct ExtractExceptionOrValueType { using Type = JS::Value; }; +template<> +struct ExtractExceptionOrValueType> { + using Type = JS::Value; +}; + template<> struct ExtractExceptionOrValueType> { using Type = JS::Value; diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 68824b541a..660828084f 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -224,7 +224,7 @@ ExceptionOr Document::set_body(HTML::HTMLElement& new_body) if (existing_body) { auto replace_result = existing_body->parent()->replace_child(new_body, *existing_body); if (replace_result.is_exception()) - return NonnullRefPtr(replace_result.exception()); + return replace_result.exception(); return {}; } @@ -234,7 +234,7 @@ ExceptionOr Document::set_body(HTML::HTMLElement& new_body) auto append_result = document_element->append_child(new_body); if (append_result.is_exception()) - return NonnullRefPtr(append_result.exception()); + return append_result.exception(); return {}; } diff --git a/Userland/Libraries/LibWeb/DOM/ExceptionOr.h b/Userland/Libraries/LibWeb/DOM/ExceptionOr.h index df1e32cee7..5b5da29b83 100644 --- a/Userland/Libraries/LibWeb/DOM/ExceptionOr.h +++ b/Userland/Libraries/LibWeb/DOM/ExceptionOr.h @@ -13,9 +13,29 @@ namespace Web::DOM { +#define ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) \ + E(EvalError) \ + E(RangeError) \ + E(ReferenceError) \ + E(TypeError) \ + E(URIError) + +#define E(x) x, +enum class SimpleExceptionType { + ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) +}; +#undef E + +struct SimpleException { + SimpleExceptionType type; + String message; +}; + template class ExceptionOr { public: + ExceptionOr() requires(IsSame) = default; + ExceptionOr(const ValueType& result) : m_result(result) { @@ -26,8 +46,18 @@ public: { } - ExceptionOr(const NonnullRefPtr exception) - : m_exception(exception) + ExceptionOr(NonnullRefPtr exception) + : m_exception(move(exception)) + { + } + + ExceptionOr(SimpleException exception) + : m_exception(move(exception)) + { + } + + ExceptionOr(Variant> exception) + : m_exception(move(exception).template downcast>()) { } @@ -35,56 +65,60 @@ public: ExceptionOr(const ExceptionOr& other) = default; ~ExceptionOr() = default; - ValueType& value() + ValueType& value() requires(!IsSame) { return m_result.value(); } - ValueType release_value() + ValueType release_value() requires(!IsSame) { return m_result.release_value(); } - const DOMException& exception() const + Variant> exception() const { - return *m_exception; + return m_exception.template downcast>(); + } + + auto materialized_exception(JS::GlobalObject& global_object) const + { +#define E(x) JS::x*, + using ResultType = Variant>; +#undef E + + return m_exception.visit( + [&](SimpleException& exception) -> ResultType { + switch (exception.type) { +#define E(x) \ + case SimpleExceptionType::x: \ + return JS::x::create(global_object, exception.message); + + ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) + +#undef E + default: + VERIFY_NOT_REACHED(); + } + }, + [&](NonnullRefPtr const& exception) -> ResultType { return exception; }, + [](Empty) -> ResultType { VERIFY_NOT_REACHED(); }); } bool is_exception() const { - return m_exception; + return !m_exception.template has(); } private: Optional m_result; - RefPtr m_exception; + // https://heycam.github.io/webidl/#idl-exceptions + Variant> m_exception { Empty {} }; }; template<> -class ExceptionOr { +class ExceptionOr : public ExceptionOr { public: - ExceptionOr(const NonnullRefPtr exception) - : m_exception(exception) - { - } - - ExceptionOr() = default; - ExceptionOr(ExceptionOr&& other) = default; - ExceptionOr(const ExceptionOr& other) = default; - ~ExceptionOr() = default; - - const DOMException& exception() const - { - return *m_exception; - } - - bool is_exception() const - { - return m_exception; - } - -private: - RefPtr m_exception; + using ExceptionOr::ExceptionOr; }; } diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index 058cd1f459..aacf3cc5b5 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -267,7 +267,7 @@ ExceptionOr> Node::pre_insert(NonnullRefPtr node, RefP { auto validity_result = ensure_pre_insertion_validity(node, child); if (validity_result.is_exception()) - return NonnullRefPtr(validity_result.exception()); + return validity_result.exception(); auto reference_child = child; if (reference_child == node)