Types.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibIDL/Types.h>
  7. namespace IDL {
  8. ParameterizedType const& Type::as_parameterized() const
  9. {
  10. return verify_cast<ParameterizedType const>(*this);
  11. }
  12. ParameterizedType& Type::as_parameterized()
  13. {
  14. return verify_cast<ParameterizedType>(*this);
  15. }
  16. UnionType const& Type::as_union() const
  17. {
  18. return verify_cast<UnionType const>(*this);
  19. }
  20. UnionType& Type::as_union()
  21. {
  22. return verify_cast<UnionType>(*this);
  23. }
  24. // https://webidl.spec.whatwg.org/#dfn-includes-a-nullable-type
  25. bool Type::includes_nullable_type() const
  26. {
  27. // A type includes a nullable type if:
  28. // - the type is a nullable type, or
  29. if (is_nullable())
  30. return true;
  31. // FIXME: - the type is an annotated type and its inner type is a nullable type, or
  32. // - the type is a union type and its number of nullable member types is 1.
  33. if (is_union() && as_union().number_of_nullable_member_types() == 1)
  34. return true;
  35. return false;
  36. }
  37. // https://webidl.spec.whatwg.org/#dfn-includes-undefined
  38. bool Type::includes_undefined() const
  39. {
  40. // A type includes undefined if:
  41. // - the type is undefined, or
  42. if (is_undefined())
  43. return true;
  44. // - the type is a nullable type and its inner type includes undefined, or
  45. // NOTE: We don't treat nullable as its own type, so this is handled by the other cases.
  46. // FIXME: - the type is an annotated type and its inner type includes undefined, or
  47. // - the type is a union type and one of its member types includes undefined.
  48. if (is_union()) {
  49. for (auto& type : as_union().member_types()) {
  50. if (type.includes_undefined())
  51. return true;
  52. }
  53. }
  54. return false;
  55. }
  56. // https://webidl.spec.whatwg.org/#dfn-distinguishable
  57. bool Type::is_distinguishable_from(IDL::Type const& other) const
  58. {
  59. // 1. If one type includes a nullable type and the other type either includes a nullable type,
  60. // is a union type with flattened member types including a dictionary type, or is a dictionary type,
  61. // return false.
  62. // FIXME: "is a union type with flattened member types including a dictionary type, or is a dictionary type,"
  63. if (includes_nullable_type() && other.includes_nullable_type())
  64. return false;
  65. // 2. If both types are either a union type or nullable union type, return true if each member type
  66. // of the one is distinguishable with each member type of the other, or false otherwise.
  67. if (is_union() && other.is_union()) {
  68. auto const& this_union = as_union();
  69. auto const& other_union = other.as_union();
  70. for (auto& this_member_type : this_union.member_types()) {
  71. for (auto& other_member_type : other_union.member_types()) {
  72. if (!this_member_type.is_distinguishable_from(other_member_type))
  73. return false;
  74. }
  75. }
  76. return true;
  77. }
  78. // 3. If one type is a union type or nullable union type, return true if each member type of the union
  79. // type is distinguishable with the non-union type, or false otherwise.
  80. if (is_union() || other.is_union()) {
  81. auto const& the_union = is_union() ? as_union() : other.as_union();
  82. auto const& non_union = is_union() ? other : *this;
  83. for (auto& member_type : the_union.member_types()) {
  84. if (!non_union.is_distinguishable_from(member_type))
  85. return false;
  86. }
  87. return true;
  88. }
  89. // 4. Consider the two "innermost" types derived by taking each type’s inner type if it is an annotated type,
  90. // and then taking its inner type inner type if the result is a nullable type. If these two innermost types
  91. // appear or are in categories appearing in the following table and there is a “●” mark in the corresponding
  92. // entry or there is a letter in the corresponding entry and the designated additional requirement below the
  93. // table is satisfied, then return true. Otherwise return false.
  94. auto const& this_innermost_type = innermost_type();
  95. auto const& other_innermost_type = other.innermost_type();
  96. enum class DistinguishabilityCategory {
  97. Undefined,
  98. Boolean,
  99. Numeric,
  100. BigInt,
  101. String,
  102. Object,
  103. Symbol,
  104. InterfaceLike,
  105. CallbackFunction,
  106. DictionaryLike,
  107. SequenceLike,
  108. __Count
  109. };
  110. // See https://webidl.spec.whatwg.org/#distinguishable-table
  111. // clang-format off
  112. static constexpr bool table[to_underlying(DistinguishabilityCategory::__Count)][to_underlying(DistinguishabilityCategory::__Count)] {
  113. {false, true, true, true, true, true, true, true, true, false, true},
  114. { true, false, true, true, true, true, true, true, true, true, true},
  115. { true, true, false, true, true, true, true, true, true, true, true},
  116. { true, true, true, false, true, true, true, true, true, true, true},
  117. { true, true, true, true, false, true, true, true, true, true, true},
  118. { true, true, true, true, true, false, true, false, false, false, false},
  119. { true, true, true, true, true, true, false, true, true, true, true},
  120. { true, true, true, true, true, false, true, false, true, true, true},
  121. { true, true, true, true, true, false, true, true, false, false, true},
  122. {false, true, true, true, true, false, true, true, false, false, true},
  123. { true, true, true, true, true, false, true, true, true, true, false},
  124. };
  125. // clang-format on
  126. auto determine_category = [](Type const& type) -> DistinguishabilityCategory {
  127. if (type.is_undefined())
  128. return DistinguishabilityCategory::Undefined;
  129. if (type.is_boolean())
  130. return DistinguishabilityCategory::Boolean;
  131. if (type.is_numeric())
  132. return DistinguishabilityCategory::Numeric;
  133. if (type.is_bigint())
  134. return DistinguishabilityCategory::BigInt;
  135. if (type.is_string())
  136. return DistinguishabilityCategory::String;
  137. if (type.is_object())
  138. return DistinguishabilityCategory::Object;
  139. if (type.is_symbol())
  140. return DistinguishabilityCategory::Symbol;
  141. // FIXME: InterfaceLike - see below
  142. // FIXME: CallbackFunction
  143. // FIXME: DictionaryLike
  144. // FIXME: Frozen array types are included in "sequence-like"
  145. if (type.is_sequence())
  146. return DistinguishabilityCategory::SequenceLike;
  147. // FIXME: For lack of a better way of determining if something is an interface type, this just assumes anything we don't recognise is one.
  148. dbgln("Unable to determine category for type named '{}', assuming it's an interface type.", type.name());
  149. return DistinguishabilityCategory::InterfaceLike;
  150. };
  151. auto this_distinguishability = determine_category(this_innermost_type);
  152. auto other_distinguishability = determine_category(other_innermost_type);
  153. if (this_distinguishability == DistinguishabilityCategory::InterfaceLike && other_distinguishability == DistinguishabilityCategory::InterfaceLike) {
  154. // Two interface-likes are distinguishable if:
  155. // "The two identified interface-like types are not the same, and no single platform object
  156. // implements both interface-like types."
  157. // FIXME: Implement this.
  158. return false;
  159. }
  160. return table[to_underlying(this_distinguishability)][to_underlying(other_distinguishability)];
  161. }
  162. }