mirror of
https://github.com/RGBCube/serenity
synced 2025-05-17 18:55:07 +00:00
LibIDL+LibWeb: Resolve distinguishing argument index at build time
Aside from the obvious performance benefits, this will allow us to properly handle dictionary types. (whose dictionary-ness is only known at build-time) Much of the rest of the overload resolution algorithm steps can (and should) be evaluated at build-time as well, but this is a good first step.
This commit is contained in:
parent
048e179572
commit
f837f02eea
4 changed files with 44 additions and 43 deletions
|
@ -1925,7 +1925,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@@overload_suffi
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webidl.spec.whatwg.org/#compute-the-effective-overload-set
|
// https://webidl.spec.whatwg.org/#compute-the-effective-overload-set
|
||||||
static EffectiveOverloadSet compute_the_effective_overload_set(auto const& overload_set)
|
static Vector<EffectiveOverloadSet::Item> compute_the_effective_overload_set(auto const& overload_set)
|
||||||
{
|
{
|
||||||
// 1. Let S be an ordered set.
|
// 1. Let S be an ordered set.
|
||||||
Vector<EffectiveOverloadSet::Item> overloads;
|
Vector<EffectiveOverloadSet::Item> overloads;
|
||||||
|
@ -2048,7 +2048,7 @@ static EffectiveOverloadSet compute_the_effective_overload_set(auto const& overl
|
||||||
overload_id++;
|
overload_id++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EffectiveOverloadSet { move(overloads) };
|
return overloads;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DeprecatedString generate_constructor_for_idl_type(Type const& type)
|
static DeprecatedString generate_constructor_for_idl_type(Type const& type)
|
||||||
|
@ -2090,6 +2090,30 @@ static DeprecatedString generate_constructor_for_idl_type(Type const& type)
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://webidl.spec.whatwg.org/#dfn-distinguishing-argument-index
|
||||||
|
static size_t resolve_distinguishing_argument_index(Vector<EffectiveOverloadSet::Item> const& items, size_t argument_count)
|
||||||
|
{
|
||||||
|
for (auto argument_index = 0u; argument_index < argument_count; ++argument_index) {
|
||||||
|
bool found_indistinguishable = false;
|
||||||
|
|
||||||
|
for (auto first_item_index = 0u; first_item_index < items.size(); ++first_item_index) {
|
||||||
|
for (auto second_item_index = first_item_index + 1; second_item_index < items.size(); ++second_item_index) {
|
||||||
|
if (!items[first_item_index].types[argument_index]->is_distinguishable_from(items[second_item_index].types[argument_index])) {
|
||||||
|
found_indistinguishable = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found_indistinguishable)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_indistinguishable)
|
||||||
|
return argument_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
static void generate_overload_arbiter(SourceGenerator& generator, auto const& overload_set, DeprecatedString const& class_name)
|
static void generate_overload_arbiter(SourceGenerator& generator, auto const& overload_set, DeprecatedString const& class_name)
|
||||||
{
|
{
|
||||||
auto function_generator = generator.fork();
|
auto function_generator = generator.fork();
|
||||||
|
@ -2102,8 +2126,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@)
|
||||||
Optional<IDL::EffectiveOverloadSet> effective_overload_set;
|
Optional<IDL::EffectiveOverloadSet> effective_overload_set;
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
auto all_possible_effective_overloads = compute_the_effective_overload_set(overload_set);
|
auto overloads_set = compute_the_effective_overload_set(overload_set);
|
||||||
auto overloads_set = all_possible_effective_overloads.items();
|
|
||||||
auto maximum_argument_count = 0u;
|
auto maximum_argument_count = 0u;
|
||||||
for (auto const& overload : overloads_set)
|
for (auto const& overload : overloads_set)
|
||||||
maximum_argument_count = max(maximum_argument_count, overload.types.size());
|
maximum_argument_count = max(maximum_argument_count, overload.types.size());
|
||||||
|
@ -2115,29 +2138,28 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@)
|
||||||
// Namely, since that discards any overloads that don't have the exact number of arguments that were given,
|
// Namely, since that discards any overloads that don't have the exact number of arguments that were given,
|
||||||
// we simply only provide the overloads that do have that number of arguments.
|
// we simply only provide the overloads that do have that number of arguments.
|
||||||
for (auto argument_count = 0u; argument_count <= maximum_argument_count; ++argument_count) {
|
for (auto argument_count = 0u; argument_count <= maximum_argument_count; ++argument_count) {
|
||||||
// FIXME: Calculate the distinguishing argument index now instead of at runtime.
|
Vector<EffectiveOverloadSet::Item> effective_overload_set;
|
||||||
|
|
||||||
auto effective_overload_count = 0;
|
|
||||||
for (auto const& overload : overloads_set) {
|
for (auto const& overload : overloads_set) {
|
||||||
if (overload.types.size() == argument_count)
|
if (overload.types.size() == argument_count)
|
||||||
effective_overload_count++;
|
effective_overload_set.append(overload);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effective_overload_count == 0)
|
if (effective_overload_set.size() == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
auto distinguishing_argument_index = 0u;
|
||||||
|
if (effective_overload_set.size() > 1)
|
||||||
|
distinguishing_argument_index = resolve_distinguishing_argument_index(effective_overload_set, argument_count);
|
||||||
|
|
||||||
function_generator.set("current_argument_count", DeprecatedString::number(argument_count));
|
function_generator.set("current_argument_count", DeprecatedString::number(argument_count));
|
||||||
function_generator.set("overload_count", DeprecatedString::number(effective_overload_count));
|
function_generator.set("overload_count", DeprecatedString::number(effective_overload_set.size()));
|
||||||
function_generator.appendln(R"~~~(
|
function_generator.appendln(R"~~~(
|
||||||
case @current_argument_count@: {
|
case @current_argument_count@: {
|
||||||
Vector<IDL::EffectiveOverloadSet::Item> overloads;
|
Vector<IDL::EffectiveOverloadSet::Item> overloads;
|
||||||
overloads.ensure_capacity(@overload_count@);
|
overloads.ensure_capacity(@overload_count@);
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
for (auto& overload : overloads_set) {
|
for (auto& overload : effective_overload_set) {
|
||||||
if (overload.types.size() != argument_count)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
StringBuilder types_builder;
|
StringBuilder types_builder;
|
||||||
types_builder.append("Vector<NonnullRefPtr<IDL::Type const>> { "sv);
|
types_builder.append("Vector<NonnullRefPtr<IDL::Type const>> { "sv);
|
||||||
StringBuilder optionality_builder;
|
StringBuilder optionality_builder;
|
||||||
|
@ -2175,8 +2197,9 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@)
|
||||||
function_generator.appendln(" overloads.empend(@overload.callable_id@, @overload.types@, @overload.optionality_values@);");
|
function_generator.appendln(" overloads.empend(@overload.callable_id@, @overload.types@, @overload.optionality_values@);");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function_generator.set("overload_set.distinguishing_argument_index", DeprecatedString::number(distinguishing_argument_index));
|
||||||
function_generator.append(R"~~~(
|
function_generator.append(R"~~~(
|
||||||
effective_overload_set.emplace(move(overloads));
|
effective_overload_set.emplace(move(overloads), @overload_set.distinguishing_argument_index@);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
|
@ -293,30 +293,6 @@ bool Type::is_json(Interface const& interface) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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()
|
void EffectiveOverloadSet::remove_all_other_entries()
|
||||||
{
|
{
|
||||||
Vector<Item> new_items;
|
Vector<Item> new_items;
|
||||||
|
|
|
@ -415,9 +415,9 @@ public:
|
||||||
Vector<Optionality> optionality_values;
|
Vector<Optionality> optionality_values;
|
||||||
};
|
};
|
||||||
|
|
||||||
EffectiveOverloadSet(Vector<Item> items)
|
EffectiveOverloadSet(Vector<Item> items, size_t distinguishing_argument_index)
|
||||||
: m_items(move(items))
|
: m_items(move(items))
|
||||||
, m_argument_count(m_items.is_empty() ? 0 : m_items.first().types.size())
|
, m_distinguishing_argument_index(distinguishing_argument_index)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +433,7 @@ public:
|
||||||
bool is_empty() const { return m_items.is_empty(); }
|
bool is_empty() const { return m_items.is_empty(); }
|
||||||
size_t size() const { return m_items.size(); }
|
size_t size() const { return m_items.size(); }
|
||||||
|
|
||||||
int distinguishing_argument_index();
|
size_t distinguishing_argument_index() const { return m_distinguishing_argument_index; }
|
||||||
|
|
||||||
template<typename Matches>
|
template<typename Matches>
|
||||||
bool has_overload_with_matching_argument_at_index(size_t index, Matches matches)
|
bool has_overload_with_matching_argument_at_index(size_t index, Matches matches)
|
||||||
|
@ -454,7 +454,7 @@ public:
|
||||||
private:
|
private:
|
||||||
// FIXME: This should be an "ordered set".
|
// FIXME: This should be an "ordered set".
|
||||||
Vector<Item> m_items;
|
Vector<Item> m_items;
|
||||||
size_t m_argument_count;
|
size_t m_distinguishing_argument_index { 0 };
|
||||||
|
|
||||||
Optional<size_t> m_last_matching_item_index;
|
Optional<size_t> m_last_matching_item_index;
|
||||||
};
|
};
|
||||||
|
|
|
@ -56,6 +56,8 @@ static bool has_overload_with_argument_type_or_subtype_matching(IDL::EffectiveOv
|
||||||
// https://webidl.spec.whatwg.org/#es-overloads
|
// https://webidl.spec.whatwg.org/#es-overloads
|
||||||
JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::EffectiveOverloadSet& overloads)
|
JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::EffectiveOverloadSet& overloads)
|
||||||
{
|
{
|
||||||
|
// FIXME: The vast majority of this algorithm can be (and must be, in order to resolve the dictionary
|
||||||
|
// related FIXMEs below) evaluated at code-generation time.
|
||||||
// 1. Let maxarg be the length of the longest type list of the entries in S.
|
// 1. Let maxarg be the length of the longest type list of the entries in S.
|
||||||
// 2. Let n be the size of args.
|
// 2. Let n be the size of args.
|
||||||
// 3. Initialize argcount to be min(maxarg, n).
|
// 3. Initialize argcount to be min(maxarg, n).
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue