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. :^)
This commit is contained in:
Sam Atkins 2022-09-08 17:19:14 +01:00 committed by Andreas Kling
parent 8b4cc07a54
commit 0d2d5ba02c
Notes: sideshowbarker 2024-07-17 09:49:33 +09:00
2 changed files with 90 additions and 0 deletions

View file

@ -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;
});
}
}

View file

@ -394,4 +394,63 @@ private:
NonnullRefPtrVector<Type> 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<Type> types;
Vector<Optionality> optionality_values;
};
EffectiveOverloadSet(Vector<Item> items)
: m_items(move(items))
, m_argument_count(m_items.is_empty() ? 0 : m_items.first().types.size())
{
}
Vector<Item>& items() { return m_items; }
Vector<Item> 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<typename Matches>
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<Item> m_items;
size_t m_argument_count;
Item const* m_last_matching_item { nullptr };
};
}