/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 | | } |