From 0d2d5ba02cdba8c4f0b72697ada7fe0a14458d65 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 8 Sep 2022 17:19:14 +0100 Subject: [PATCH] LibIDL: Implement EffectiveOverloadSet This requires a little explanation. The overload resolution algorithm, where this is used, repeatedly has steps like this: > Otherwise: if V is a platform object, and there is an entry in S that > has one of the following types at position i of its type list, > - an interface type that V implements > - object > - a nullable version of any of the above types > - an annotated type whose inner type is one of the above types > - a union type, nullable union type, or annotated union type that has > one of the above types in its flattened member types > then remove from S all other entries. So, the API here tries to match that. We save the matching entry when checking through them and then use that in `remove_all_other_entries()`. Removing all those entries when all we actually care about is looking at that one matching entry feels silly, but sticking to the spec is more important while things are still half-implemented. :^) --- Userland/Libraries/LibIDL/Types.cpp | 31 +++++++++++++++ Userland/Libraries/LibIDL/Types.h | 59 +++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/Userland/Libraries/LibIDL/Types.cpp b/Userland/Libraries/LibIDL/Types.cpp index 09df15d7d4..41eef5e817 100644 --- a/Userland/Libraries/LibIDL/Types.cpp +++ b/Userland/Libraries/LibIDL/Types.cpp @@ -188,4 +188,35 @@ bool Type::is_distinguishable_from(IDL::Type const& other) const return table[to_underlying(this_distinguishability)][to_underlying(other_distinguishability)]; } +// https://webidl.spec.whatwg.org/#dfn-distinguishing-argument-index +int EffectiveOverloadSet::distinguishing_argument_index() +{ + for (auto argument_index = 0u; argument_index < m_argument_count; ++argument_index) { + bool found_indistinguishable = false; + + for (auto first_item_index = 0u; first_item_index < m_items.size(); ++first_item_index) { + for (auto second_item_index = first_item_index + 1; second_item_index < m_items.size(); ++second_item_index) { + if (!m_items[first_item_index].types[argument_index].is_distinguishable_from(m_items[second_item_index].types[argument_index])) { + found_indistinguishable = true; + break; + } + } + if (found_indistinguishable) + break; + } + + if (!found_indistinguishable) + return argument_index; + } + + VERIFY_NOT_REACHED(); +} + +void EffectiveOverloadSet::remove_all_other_entries() +{ + m_items.remove_all_matching([this](auto const& item) { + return &item != m_last_matching_item; + }); +} + } diff --git a/Userland/Libraries/LibIDL/Types.h b/Userland/Libraries/LibIDL/Types.h index f800203c2a..133f077f82 100644 --- a/Userland/Libraries/LibIDL/Types.h +++ b/Userland/Libraries/LibIDL/Types.h @@ -394,4 +394,63 @@ private: NonnullRefPtrVector m_member_types; }; +// https://webidl.spec.whatwg.org/#dfn-optionality-value +enum class Optionality { + Required, + Optional, + Variadic, +}; + +// https://webidl.spec.whatwg.org/#dfn-effective-overload-set +class EffectiveOverloadSet { +public: + struct Item { + int callable_id; + NonnullRefPtrVector types; + Vector optionality_values; + }; + + EffectiveOverloadSet(Vector items) + : m_items(move(items)) + , m_argument_count(m_items.is_empty() ? 0 : m_items.first().types.size()) + { + } + + Vector& items() { return m_items; } + Vector const& items() const { return m_items; } + + Item const& only_item() const + { + VERIFY(m_items.size() == 1); + return m_items[0]; + } + + bool is_empty() const { return m_items.is_empty(); } + size_t size() const { return m_items.size(); } + + int distinguishing_argument_index(); + + template + bool has_overload_with_matching_argument_at_index(size_t index, Matches matches) + { + for (auto const& item : m_items) { + if (matches(item.types[index], item.optionality_values[index])) { + m_last_matching_item = &item; + return true; + } + } + m_last_matching_item = nullptr; + return false; + } + + void remove_all_other_entries(); + +private: + // FIXME: This should be an "ordered set". + Vector m_items; + size_t m_argument_count; + + Item const* m_last_matching_item { nullptr }; +}; + }