From 8ba2b5f36f5420402b71d5eaf90aa2961a0705d2 Mon Sep 17 00:00:00 2001 From: AnotherTest Date: Tue, 13 Apr 2021 23:48:25 +0430 Subject: [PATCH] LibWeb: Make ExceptionOr work with non-JS::Value types Fixes #6075. --- .../LibWeb/Bindings/ExceptionOrUtils.h | 45 ++++++++++++++++--- .../CodeGenerators/WrapperGenerator.cpp | 6 ++- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h b/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h index 463e3bc495..081c04f21e 100644 --- a/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h +++ b/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h @@ -26,6 +26,7 @@ #pragma once +#include #include #include #include @@ -49,16 +50,48 @@ ALWAYS_INLINE bool throw_dom_exception(JS::VM& vm, JS::GlobalObject& global_obje return false; } -template()()), typename Ret = Conditional && !IsVoid, T, JS::Value>> -Ret throw_dom_exception_if_needed(auto&& vm, auto&& global_object, F&& fn) +namespace Detail { + +template +struct ExtractExceptionOrValueType { + using Type = T; +}; + +template +struct ExtractExceptionOrValueType> { + using Type = T; +}; + +template<> +struct ExtractExceptionOrValueType { + using Type = JS::Value; +}; + +template<> +struct ExtractExceptionOrValueType> { + using Type = JS::Value; +}; + +} + +template +using ExtractExceptionOrValueType = typename Detail::ExtractExceptionOrValueType::Type; + +// Return type depends on the return type of 'fn' (when invoked with no args): +// void or ExceptionOr: Optional, always returns JS::js_undefined() +// ExceptionOr: Optional +// T: Optional +template()()), typename Ret = Conditional && !IsVoid, T, ExtractExceptionOrValueType>> +Optional throw_dom_exception_if_needed(auto&& vm, auto&& global_object, F&& fn) { if constexpr (IsExceptionOr) { auto&& result = fn(); if (throw_dom_exception(vm, global_object, result)) - return JS::Value(); + return {}; if constexpr (requires(T v) { v.value(); }) return result.value(); - return JS::Value(); + else + return JS::js_undefined(); } else if constexpr (IsVoid) { fn(); return JS::js_undefined(); @@ -68,10 +101,10 @@ Ret throw_dom_exception_if_needed(auto&& vm, auto&& global_object, F&& fn) } template -bool should_return_empty(T&& value) +bool should_return_empty(const Optional& value) { if constexpr (IsSame) - return value.is_empty(); + return value.has_value() && value.value().is_empty(); return false; } diff --git a/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp b/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp index 611fe08135..555e0d4c58 100644 --- a/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp +++ b/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp @@ -1514,9 +1514,11 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@function.name:snakecase@) function_generator.set(".arguments", arguments_builder.string_view()); function_generator.append(R"~~~( - auto retval = throw_dom_exception_if_needed(vm, global_object, [&] { return impl->@function.cpp_name@(@.arguments@); }); - if (should_return_empty(retval)) + auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl->@function.cpp_name@(@.arguments@); }); + if (should_return_empty(result)) return JS::Value(); + + [[maybe_unused]] auto retval = result.release_value(); )~~~"); generate_return_statement(function.return_type);