Coverage Report

Created: 2025-09-05 06:52

/src/serenity/Userland/Libraries/LibWeb/WebIDL/OverloadResolution.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <LibJS/Runtime/ArrayBuffer.h>
8
#include <LibJS/Runtime/DataView.h>
9
#include <LibJS/Runtime/FunctionObject.h>
10
#include <LibJS/Runtime/TypedArray.h>
11
#include <LibJS/Runtime/Value.h>
12
#include <LibWeb/Bindings/PlatformObject.h>
13
#include <LibWeb/WebIDL/OverloadResolution.h>
14
15
namespace Web::WebIDL {
16
17
// https://webidl.spec.whatwg.org/#dfn-convert-ecmascript-to-idl-value
18
static JS::Value convert_ecmascript_type_to_idl_value(JS::Value value, IDL::Type const&)
19
0
{
20
    // FIXME: We have this code already in the code generator, in `generate_to_cpp()`, but how do we use it here?
21
0
    return value;
22
0
}
23
24
template<typename Match>
25
static bool has_overload_with_argument_type_or_subtype_matching(IDL::EffectiveOverloadSet& overloads, size_t argument_index, Match match)
26
0
{
27
    // NOTE: This is to save some repetition.
28
    //       Almost every sub-step of step 12 of the overload resolution algorithm matches overloads with an argument that is:
29
    //       - One of several specific types.
30
    //       - "an annotated type whose inner type is one of the above types"
31
    //       - "a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types"
32
    //       So, this function lets you pass in the first check, and handles the others automatically.
33
34
0
    return overloads.has_overload_with_matching_argument_at_index(argument_index,
35
0
        [match](IDL::Type const& type, auto) {
36
0
            if (match(type))
37
0
                return true;
38
39
            // FIXME: - an annotated type whose inner type is one of the above types
40
41
0
            if (type.is_union()) {
42
0
                auto flattened_members = type.as_union().flattened_member_types();
43
0
                for (auto const& member : flattened_members) {
44
0
                    if (match(member))
45
0
                        return true;
46
47
                    // FIXME: - an annotated type whose inner type is one of the above types
48
0
                }
49
0
                return false;
50
0
            }
51
52
0
            return false;
53
0
        });
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_3>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_3)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_4>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_4)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_5>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_5)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_6>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_6)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_7>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_7)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_8>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_8)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_9>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_9)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_10>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_10)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_11>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_11)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_12>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_12)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_13>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_13)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_14>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_14)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
Unexecuted instantiation: OverloadResolution.cpp:auto Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_15>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_15)::{lambda(IDL::Type const&, auto:1)#1}::operator()<IDL::Optionality>(IDL::Type const&, IDL::Optionality) const
54
0
}
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_3>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_3)
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_4>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_4)
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_5>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_5)
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_6>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_6)
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_7>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_7)
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_8>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_8)
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_9>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_9)
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_10>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_10)
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_11>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_11)
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_12>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_12)
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_13>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_13)
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_14>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_14)
Unexecuted instantiation: OverloadResolution.cpp:bool Web::WebIDL::has_overload_with_argument_type_or_subtype_matching<Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_15>(IDL::EffectiveOverloadSet&, unsigned long, Web::WebIDL::resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, AK::Span<AK::StringView const>)::$_15)
55
56
// https://webidl.spec.whatwg.org/#es-overloads
57
JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::EffectiveOverloadSet& overloads, ReadonlySpan<StringView> dictionary_types)
58
0
{
59
0
    auto is_dictionary = [&dictionary_types](IDL::Type const& type) {
60
0
        return dictionary_types.contains_slow(type.name());
61
0
    };
62
63
    // 1. Let maxarg be the length of the longest type list of the entries in S.
64
    // 2. Let n be the size of args.
65
    // 3. Initialize argcount to be min(maxarg, n).
66
    // 4. Remove from S all entries whose type list is not of length argcount.
67
    // NOTE: The IDL-generated callers already only provide an overload set containing overloads with the correct number
68
    //       of arguments. Therefore, we do not need to remove any entry from that set here. However, we do need to handle
69
    //       when the number of user-provided arguments exceeds the overload set's argument count.
70
0
    int argument_count = min(vm.argument_count(), overloads.is_empty() ? 0 : overloads.items()[0].types.size());
71
72
    // 5. If S is empty, then throw a TypeError.
73
0
    if (overloads.is_empty())
74
0
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::OverloadResolutionFailed);
75
76
    // 6. Initialize d to −1.
77
0
    auto distinguishing_argument_index = -1;
78
79
    // 7. Initialize method to undefined.
80
0
    Optional<JS::FunctionObject&> method;
81
82
    // 8. If there is more than one entry in S, then set d to be the distinguishing argument index for the entries of S.
83
0
    if (overloads.size() > 1)
84
0
        distinguishing_argument_index = overloads.distinguishing_argument_index();
85
86
    // 9. Initialize values to be an empty list, where each entry will be either an IDL value or the special value “missing”.
87
0
    Vector<ResolvedOverload::Argument> values;
88
89
    // 10. Initialize i to 0.
90
0
    auto i = 0;
91
92
    // 11. While i < d:
93
0
    while (i < distinguishing_argument_index) {
94
        // 1. Let V be args[i].
95
0
        auto const& value = vm.argument(i);
96
97
0
        auto const& item = overloads.items().first();
98
99
        // 2. Let type be the type at index i in the type list of any entry in S.
100
0
        auto const& type = item.types[i];
101
102
        // 3. Let optionality be the value at index i in the list of optionality values of any entry in S.
103
0
        auto const& optionality = item.optionality_values[i];
104
105
        // 4. If optionality is “optional” and V is undefined, then:
106
0
        if (optionality == IDL::Optionality::Optional && value.is_undefined()) {
107
            // FIXME: 1. If the argument at index i is declared with a default value, then append to values that default value.
108
109
            // 2. Otherwise, append to values the special value “missing”.
110
0
            values.empend(ResolvedOverload::Missing {});
111
0
        }
112
113
        // 5. Otherwise, append to values the result of converting V to IDL type type.
114
0
        values.empend(convert_ecmascript_type_to_idl_value(value, type));
115
116
        // 6. Set i to i + 1.
117
0
        ++i;
118
0
    }
119
120
    // 12. If i = d, then:
121
0
    if (i == distinguishing_argument_index) {
122
        // 1. Let V be args[i].
123
0
        auto const& value = vm.argument(i);
124
125
        // 2. If V is undefined, and there is an entry in S whose list of optionality values has “optional” at index i, then remove from S all other entries.
126
0
        if (value.is_undefined()
127
0
            && overloads.has_overload_with_matching_argument_at_index(i, [](auto&, IDL::Optionality const& optionality) { return optionality == IDL::Optionality::Optional; })) {
128
0
            overloads.remove_all_other_entries();
129
0
        }
130
131
        // 3. Otherwise: if V is null or undefined, and there is an entry in S that has one of the following types at position i of its type list,
132
        //    - a nullable type
133
        //    - a dictionary type
134
        //    - an annotated type whose inner type is one of the above types
135
        //    - a union type or annotated union type that includes a nullable type or that has a dictionary type in its flattened members
136
        //    then remove from S all other entries.
137
        // NOTE: This is the one case we can't use `has_overload_with_argument_type_or_subtype_matching()` because we also need to look
138
        //       for dictionary types in the flattened members.
139
0
        else if ((value.is_undefined() || value.is_null())
140
0
            && overloads.has_overload_with_matching_argument_at_index(i, [&is_dictionary](IDL::Type const& type, auto) {
141
0
                   if (type.is_nullable())
142
0
                       return true;
143
0
                   if (is_dictionary(type))
144
0
                       return true;
145
146
                   // FIXME: - an annotated type whose inner type is one of the above types
147
0
                   if (type.is_union()) {
148
0
                       auto flattened_members = type.as_union().flattened_member_types();
149
0
                       for (auto const& member : flattened_members) {
150
0
                           if (member->is_nullable())
151
0
                               return true;
152
0
                           if (is_dictionary(type))
153
0
                               return true;
154
                           // FIXME: - an annotated type whose inner type is one of the above types
155
0
                       }
156
0
                       return false;
157
0
                   }
158
0
                   return false;
159
0
               })) {
160
0
            overloads.remove_all_other_entries();
161
0
        }
162
163
        // 4. 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,
164
        //    - an interface type that V implements
165
        //    - object
166
        //    - a nullable version of any of the above types
167
        //    - an annotated type whose inner type is one of the above types
168
        //    - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
169
        //    then remove from S all other entries.
170
0
        else if (value.is_object() && is<Bindings::PlatformObject>(value.as_object())
171
0
            && has_overload_with_argument_type_or_subtype_matching(overloads, i, [value](IDL::Type const& type) {
172
                   // - an interface type that V implements
173
0
                   if (static_cast<Bindings::PlatformObject const&>(value.as_object()).implements_interface(MUST(String::from_byte_string(type.name()))))
174
0
                       return true;
175
176
                   // - object
177
0
                   if (type.is_object())
178
0
                       return true;
179
180
0
                   return false;
181
0
               })) {
182
0
            overloads.remove_all_other_entries();
183
0
        }
184
185
        // 5. Otherwise: if Type(V) is Object, V has an [[ArrayBufferData]] internal slot, and there is an entry in S that has one of the following types at position i of its type list,
186
        //    - ArrayBuffer
187
        //    - object
188
        //    - a nullable version of either of the above types
189
        //    - an annotated type whose inner type is one of the above types
190
        //    - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
191
        //    then remove from S all other entries.
192
0
        else if (value.is_object() && is<JS::ArrayBuffer>(value.as_object())
193
0
            && has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) {
194
0
                   if (type.is_plain() && (type.name() == "ArrayBuffer" || type.name() == "BufferSource"))
195
0
                       return true;
196
0
                   if (type.is_object())
197
0
                       return true;
198
0
                   return false;
199
0
               })) {
200
0
            overloads.remove_all_other_entries();
201
0
        }
202
203
        // 6. Otherwise: if Type(V) is Object, V has a [[DataView]] internal slot, and there is an entry in S that has one of the following types at position i of its type list,
204
        //    - DataView
205
        //    - object
206
        //    - a nullable version of either of the above types
207
        //    - an annotated type whose inner type is one of the above types
208
        //    - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
209
        //    then remove from S all other entries.
210
0
        else if (value.is_object() && is<JS::DataView>(value.as_object())
211
0
            && has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) {
212
0
                   if (type.is_plain() && (type.name() == "DataView" || type.name() == "BufferSource"))
213
0
                       return true;
214
0
                   if (type.is_object())
215
0
                       return true;
216
0
                   return false;
217
0
               })) {
218
0
            overloads.remove_all_other_entries();
219
0
        }
220
221
        // 7. Otherwise: if Type(V) is Object, V has a [[TypedArrayName]] internal slot, and there is an entry in S that has one of the following types at position i of its type list,
222
        //    - a typed array type whose name is equal to the value of V’s [[TypedArrayName]] internal slot
223
        //    - object
224
        //    - a nullable version of either of the above types
225
        //    - an annotated type whose inner type is one of the above types
226
        //    - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
227
        //    then remove from S all other entries.
228
0
        else if (value.is_object() && value.as_object().is_typed_array()
229
0
            && has_overload_with_argument_type_or_subtype_matching(overloads, i, [&](IDL::Type const& type) {
230
0
                   if (type.is_plain() && (type.name() == static_cast<JS::TypedArrayBase const&>(value.as_object()).element_name() || type.name() == "BufferSource"))
231
0
                       return true;
232
0
                   if (type.is_object())
233
0
                       return true;
234
0
                   return false;
235
0
               })) {
236
0
            overloads.remove_all_other_entries();
237
0
        }
238
239
        // 8. Otherwise: if IsCallable(V) is true, and there is an entry in S that has one of the following types at position i of its type list,
240
        //    - a callback function type
241
        //    - object
242
        //    - a nullable version of any of the above types
243
        //    - an annotated type whose inner type is one of the above types
244
        //    - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
245
        //    then remove from S all other entries.
246
0
        else if (value.is_function()
247
0
            && has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) {
248
                   // FIXME: - a callback function type
249
0
                   if (type.is_object())
250
0
                       return true;
251
0
                   return false;
252
0
               })) {
253
0
            overloads.remove_all_other_entries();
254
0
        }
255
256
        // FIXME: 9. Otherwise: if Type(V) is Object and there is an entry in S that has one of the following types at position i of its type list,
257
        //    - a sequence type
258
        //    - a frozen array type
259
        //    - a nullable version of any of the above types
260
        //    - an annotated type whose inner type is one of the above types
261
        //    - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
262
        //    and after performing the following steps,
263
        //    {
264
        //        1. Let method be ? GetMethod(V, @@iterator).
265
        //    }
266
        //    method is not undefined, then remove from S all other entries.
267
268
        // 10. Otherwise: if Type(V) is Object and there is an entry in S that has one of the following types at position i of its type list,
269
        //     - a callback interface type
270
        //     - a dictionary type
271
        //     - a record type
272
        //     - object
273
        //     - a nullable version of any of the above types
274
        //     - an annotated type whose inner type is one of the above types
275
        //     - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
276
        //     then remove from S all other entries.
277
0
        else if (value.is_object()
278
0
            && has_overload_with_argument_type_or_subtype_matching(overloads, i, [&is_dictionary](IDL::Type const& type) {
279
0
                   if (is_dictionary(type))
280
0
                       return true;
281
                   // FIXME: a callback interface type
282
                   // FIXME: a record type
283
0
                   return type.is_object();
284
0
               })) {
285
0
            overloads.remove_all_other_entries();
286
0
        }
287
288
        // 11. Otherwise: if Type(V) is Boolean and there is an entry in S that has one of the following types at position i of its type list,
289
        //     - boolean
290
        //     - a nullable boolean
291
        //     - an annotated type whose inner type is one of the above types
292
        //     - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
293
        //     then remove from S all other entries.
294
0
        else if (value.is_boolean()
295
0
            && has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_boolean(); })) {
296
0
            overloads.remove_all_other_entries();
297
0
        }
298
299
        // 12. Otherwise: if Type(V) is Number and there is an entry in S that has one of the following types at position i of its type list,
300
        //     - a numeric type
301
        //     - a nullable numeric type
302
        //     - an annotated type whose inner type is one of the above types
303
        //     - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
304
        //     then remove from S all other entries.
305
0
        else if (value.is_number()
306
0
            && has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_numeric(); })) {
307
0
            overloads.remove_all_other_entries();
308
0
        }
309
310
        // 13. Otherwise: if Type(V) is BigInt and there is an entry in S that has one of the following types at position i of its type list,
311
        //     - bigint
312
        //     - a nullable bigint
313
        //     - an annotated type whose inner type is one of the above types
314
        //     - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
315
        //     then remove from S all other entries.
316
0
        else if (value.is_bigint()
317
0
            && has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_bigint(); })) {
318
0
            overloads.remove_all_other_entries();
319
0
        }
320
321
        // 14. Otherwise: if there is an entry in S that has one of the following types at position i of its type list,
322
        //     - a string type
323
        //     - a nullable version of any of the above types
324
        //     - an annotated type whose inner type is one of the above types
325
        //     - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
326
        //     then remove from S all other entries.
327
0
        else if (has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_string(); })) {
328
0
            overloads.remove_all_other_entries();
329
0
        }
330
331
        // 15. Otherwise: if there is an entry in S that has one of the following types at position i of its type list,
332
        //     - a numeric type
333
        //     - a nullable numeric type
334
        //     - an annotated type whose inner type is one of the above types
335
        //     - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
336
        //     then remove from S all other entries.
337
0
        else if (has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_numeric(); })) {
338
0
            overloads.remove_all_other_entries();
339
0
        }
340
341
        // 16. Otherwise: if there is an entry in S that has one of the following types at position i of its type list,
342
        //     - boolean
343
        //     - a nullable boolean
344
        //     - an annotated type whose inner type is one of the above types
345
        //     - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
346
        //     then remove from S all other entries.
347
0
        else if (has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_boolean(); })) {
348
0
            overloads.remove_all_other_entries();
349
0
        }
350
351
        // 17. Otherwise: if there is an entry in S that has one of the following types at position i of its type list,
352
        //     - bigint
353
        //     - a nullable bigint
354
        //     - an annotated type whose inner type is one of the above types
355
        //     - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
356
        //     then remove from S all other entries.
357
0
        else if (has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_bigint(); })) {
358
0
            overloads.remove_all_other_entries();
359
0
        }
360
361
        // 18. Otherwise: if there is an entry in S that has any at position i of its type list, then remove from S all other entries.
362
0
        else if (overloads.has_overload_with_matching_argument_at_index(i, [](auto const& type, auto) { return type->is_any(); })) {
363
0
            overloads.remove_all_other_entries();
364
0
        }
365
366
        // 19. Otherwise: throw a TypeError.
367
0
        else {
368
            // FIXME: Remove this message once all the above sub-steps are implemented.
369
0
            dbgln("Failed to determine IDL overload. (Probably because of unimplemented steps.)");
370
0
            return vm.throw_completion<JS::TypeError>(JS::ErrorType::OverloadResolutionFailed);
371
0
        }
372
0
    }
373
374
    // 13. Let callable be the operation or extended attribute of the single entry in S.
375
0
    auto const& callable = overloads.only_item();
376
377
    // 14. If i = d and method is not undefined, then
378
0
    if (i == distinguishing_argument_index && method.has_value()) {
379
        // 1. Let V be args[i].
380
0
        auto const& value = vm.argument(i);
381
382
        // 2. Let T be the type at index i in the type list of the remaining entry in S.
383
0
        auto const& type = overloads.only_item().types[i];
384
385
0
        (void)value;
386
0
        (void)type;
387
        // FIXME: 3. If T is a sequence type, then append to values the result of creating a sequence of type T from V and method.
388
389
        // FIXME: 4. Otherwise, T is a frozen array type. Append to values the result of creating a frozen array of type T from V and method.
390
391
        // 5. Set i to i + 1.
392
0
        ++i;
393
0
    }
394
395
    // 15. While i < argcount:
396
0
    while (i < argument_count) {
397
        // 1. Let V be args[i].
398
0
        auto const& value = vm.argument(i);
399
400
        // 2. Let type be the type at index i in the type list of the remaining entry in S.
401
0
        auto const& entry = overloads.only_item();
402
0
        auto const& type = entry.types[i];
403
404
        // 3. Let optionality be the value at index i in the list of optionality values of the remaining entry in S.
405
0
        auto const& optionality = entry.optionality_values[i];
406
407
        // 4. If optionality is “optional” and V is undefined, then:
408
0
        if (optionality == IDL::Optionality::Optional && value.is_undefined()) {
409
            // FIXME: 1. If the argument at index i is declared with a default value, then append to values that default value.
410
411
            // 2. Otherwise, append to values the special value “missing”.
412
0
            values.empend(ResolvedOverload::Missing {});
413
0
        }
414
415
        // 5. Otherwise, append to values the result of converting V to IDL type type.
416
0
        else {
417
0
            values.append(convert_ecmascript_type_to_idl_value(value, type));
418
0
        }
419
420
        // 6. Set i to i + 1.
421
0
        ++i;
422
0
    }
423
424
    // 16. While i is less than the number of arguments callable is declared to take:
425
0
    while (i < static_cast<int>(callable.types.size())) {
426
        // FIXME: 1. If callable’s argument at index i is declared with a default value, then append to values that default value.
427
0
        if (false) {
428
0
        }
429
430
        // 2. Otherwise, if callable’s argument at index i is not variadic, then append to values the special value “missing”.
431
0
        else if (callable.optionality_values[i] != IDL::Optionality::Variadic) {
432
0
            values.empend(ResolvedOverload::Missing {});
433
0
        }
434
435
        // 3. Set i to i + 1.
436
0
        ++i;
437
0
    }
438
439
    // 17. Return the pair <callable, values>.
440
0
    return ResolvedOverload { callable.callable_id, move(values) };
441
0
}
442
443
}