OverloadResolution.cpp 24 KB

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