OverloadResolution.cpp 22 KB

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