LibIDL+WrapperGenerator: Implement Type::is_distinguishable_from()

As part of this, I've moved a couple of methods for checking for
null/undefined from UnionType to Type, and filled in more of their
steps.

This now detects more, and so causes us to hit a `TODO()` which is too
big for me to go after right now, so I've replaced that assertion with
a log message.
This commit is contained in:
Sam Atkins 2022-09-07 15:27:08 +01:00 committed by Andreas Kling
parent 7c8ef79898
commit 8b4cc07a54
Notes: sideshowbarker 2024-07-17 06:53:45 +09:00
3 changed files with 217 additions and 37 deletions

View file

@ -1019,7 +1019,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
// FIXME: 2. If the union type includes a nullable type and V is null or undefined, then return the IDL value null.
if (union_type.includes_nullable_type()) {
TODO();
dbgln("FIXME: 2. If the union type includes a nullable type and V is null or undefined, then return the IDL value null.");
} else if (dictionary_type) {
// 4. If V is null or undefined, then
// 4.1 If types includes a dictionary type, then return the result of converting V to that dictionary type.

View file

@ -28,4 +28,164 @@ UnionType& Type::as_union()
return verify_cast<UnionType>(*this);
}
// https://webidl.spec.whatwg.org/#dfn-includes-a-nullable-type
bool Type::includes_nullable_type() const
{
// A type includes a nullable type if:
// - the type is a nullable type, or
if (is_nullable())
return true;
// FIXME: - the type is an annotated type and its inner type is a nullable type, or
// - the type is a union type and its number of nullable member types is 1.
if (is_union() && as_union().number_of_nullable_member_types() == 1)
return true;
return false;
}
// https://webidl.spec.whatwg.org/#dfn-includes-undefined
bool Type::includes_undefined() const
{
// A type includes undefined if:
// - the type is undefined, or
if (is_undefined())
return true;
// - the type is a nullable type and its inner type includes undefined, or
// NOTE: We don't treat nullable as its own type, so this is handled by the other cases.
// FIXME: - the type is an annotated type and its inner type includes undefined, or
// - the type is a union type and one of its member types includes undefined.
if (is_union()) {
for (auto& type : as_union().member_types()) {
if (type.includes_undefined())
return true;
}
}
return false;
}
// https://webidl.spec.whatwg.org/#dfn-distinguishable
bool Type::is_distinguishable_from(IDL::Type const& other) const
{
// 1. If one type includes a nullable type and the other type either includes a nullable type,
// is a union type with flattened member types including a dictionary type, or is a dictionary type,
// return false.
// FIXME: "is a union type with flattened member types including a dictionary type, or is a dictionary type,"
if (includes_nullable_type() && other.includes_nullable_type())
return false;
// 2. If both types are either a union type or nullable union type, return true if each member type
// of the one is distinguishable with each member type of the other, or false otherwise.
if (is_union() && other.is_union()) {
auto const& this_union = as_union();
auto const& other_union = other.as_union();
for (auto& this_member_type : this_union.member_types()) {
for (auto& other_member_type : other_union.member_types()) {
if (!this_member_type.is_distinguishable_from(other_member_type))
return false;
}
}
return true;
}
// 3. If one type is a union type or nullable union type, return true if each member type of the union
// type is distinguishable with the non-union type, or false otherwise.
if (is_union() || other.is_union()) {
auto const& the_union = is_union() ? as_union() : other.as_union();
auto const& non_union = is_union() ? other : *this;
for (auto& member_type : the_union.member_types()) {
if (!non_union.is_distinguishable_from(member_type))
return false;
}
return true;
}
// 4. Consider the two "innermost" types derived by taking each types inner type if it is an annotated type,
// and then taking its inner type inner type if the result is a nullable type. If these two innermost types
// appear or are in categories appearing in the following table and there is a “●” mark in the corresponding
// entry or there is a letter in the corresponding entry and the designated additional requirement below the
// table is satisfied, then return true. Otherwise return false.
auto const& this_innermost_type = innermost_type();
auto const& other_innermost_type = other.innermost_type();
enum class DistinguishabilityCategory {
Undefined,
Boolean,
Numeric,
BigInt,
String,
Object,
Symbol,
InterfaceLike,
CallbackFunction,
DictionaryLike,
SequenceLike,
__Count
};
// See https://webidl.spec.whatwg.org/#distinguishable-table
// clang-format off
static constexpr bool table[to_underlying(DistinguishabilityCategory::__Count)][to_underlying(DistinguishabilityCategory::__Count)] {
{false, true, true, true, true, true, true, true, true, false, true},
{ true, false, true, true, true, true, true, true, true, true, true},
{ true, true, false, true, true, true, true, true, true, true, true},
{ true, true, true, false, true, true, true, true, true, true, true},
{ true, true, true, true, false, true, true, true, true, true, true},
{ true, true, true, true, true, false, true, false, false, false, false},
{ true, true, true, true, true, true, false, true, true, true, true},
{ true, true, true, true, true, false, true, false, true, true, true},
{ true, true, true, true, true, false, true, true, false, false, true},
{false, true, true, true, true, false, true, true, false, false, true},
{ true, true, true, true, true, false, true, true, true, true, false},
};
// clang-format on
auto determine_category = [](Type const& type) -> DistinguishabilityCategory {
if (type.is_undefined())
return DistinguishabilityCategory::Undefined;
if (type.is_boolean())
return DistinguishabilityCategory::Boolean;
if (type.is_numeric())
return DistinguishabilityCategory::Numeric;
if (type.is_bigint())
return DistinguishabilityCategory::BigInt;
if (type.is_string())
return DistinguishabilityCategory::String;
if (type.is_object())
return DistinguishabilityCategory::Object;
if (type.is_symbol())
return DistinguishabilityCategory::Symbol;
// FIXME: InterfaceLike - see below
// FIXME: CallbackFunction
// FIXME: DictionaryLike
// FIXME: Frozen array types are included in "sequence-like"
if (type.is_sequence())
return DistinguishabilityCategory::SequenceLike;
// 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.
dbgln("Unable to determine category for type named '{}', assuming it's an interface type.", type.name());
return DistinguishabilityCategory::InterfaceLike;
};
auto this_distinguishability = determine_category(this_innermost_type);
auto other_distinguishability = determine_category(other_innermost_type);
if (this_distinguishability == DistinguishabilityCategory::InterfaceLike && other_distinguishability == DistinguishabilityCategory::InterfaceLike) {
// Two interface-likes are distinguishable if:
// "The two identified interface-like types are not the same, and no single platform object
// implements both interface-like types."
// FIXME: Implement this.
return false;
}
return table[to_underlying(this_distinguishability)][to_underlying(other_distinguishability)];
}
}

View file

@ -71,21 +71,7 @@ public:
Kind kind() const { return m_kind; }
String const& name() const { return m_name; }
bool is_nullable() const { return m_nullable; }
void set_nullable(bool value) { m_nullable = value; }
bool is_string() const { return m_name.is_one_of("ByteString", "CSSOMString", "DOMString", "USVString"); }
// https://webidl.spec.whatwg.org/#dfn-integer-type
bool is_integer() const { return m_name.is_one_of("byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long", "unsigned long long"); }
// https://webidl.spec.whatwg.org/#dfn-numeric-type
bool is_numeric() const { return is_integer() || m_name.is_one_of("float", "unrestricted float", "double", "unrestricted double"); }
// https://webidl.spec.whatwg.org/#dfn-primitive-type
bool is_primitive() const { return is_numeric() || m_name.is_one_of("bigint", "boolean"); }
bool is_plain() const { return m_kind == Kind::Plain; }
bool is_parameterized() const { return m_kind == Kind::Parameterized; }
ParameterizedType const& as_parameterized() const;
@ -95,6 +81,61 @@ public:
UnionType const& as_union() const;
UnionType& as_union();
String const& name() const { return m_name; }
bool is_nullable() const { return m_nullable; }
void set_nullable(bool value) { m_nullable = value; }
// https://webidl.spec.whatwg.org/#dfn-includes-a-nullable-type
bool includes_nullable_type() const;
// -> https://webidl.spec.whatwg.org/#dfn-includes-undefined
bool includes_undefined() const;
Type const& innermost_type() const
{
// From step 4 of https://webidl.spec.whatwg.org/#dfn-distinguishable
// "Consider the two "innermost" types derived by taking each types inner type if it is an annotated type, and then taking its inner type inner type if the result is a nullable type."
// FIXME: Annotated types.
VERIFY(!is_union());
return *this;
}
// https://webidl.spec.whatwg.org/#idl-any
bool is_any() const { return is_plain() && m_name == "any"; }
// https://webidl.spec.whatwg.org/#idl-undefined
bool is_undefined() const { return is_plain() && m_name == "undefined"; }
// https://webidl.spec.whatwg.org/#idl-boolean
bool is_boolean() const { return is_plain() && m_name == "boolean"; }
// https://webidl.spec.whatwg.org/#idl-bigint
bool is_bigint() const { return is_plain() && m_name == "bigint"; }
// https://webidl.spec.whatwg.org/#idl-object
bool is_object() const { return is_plain() && m_name == "object"; }
// https://webidl.spec.whatwg.org/#idl-symbol
bool is_symbol() const { return is_plain() && m_name == "symbol"; }
bool is_string() const { return is_plain() && m_name.is_one_of("ByteString", "CSSOMString", "DOMString", "USVString"); }
// https://webidl.spec.whatwg.org/#dfn-integer-type
bool is_integer() const { return is_plain() && m_name.is_one_of("byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long", "unsigned long long"); }
// https://webidl.spec.whatwg.org/#dfn-numeric-type
bool is_numeric() const { return is_plain() && (is_integer() || m_name.is_one_of("float", "unrestricted float", "double", "unrestricted double")); }
// https://webidl.spec.whatwg.org/#dfn-primitive-type
bool is_primitive() const { return is_plain() && (is_numeric() || is_boolean() || m_name == "bigint"); }
// https://webidl.spec.whatwg.org/#idl-sequence
bool is_sequence() const { return is_parameterized() && m_name == "sequence"; }
// https://webidl.spec.whatwg.org/#dfn-distinguishable
bool is_distinguishable_from(Type const& other) const;
private:
Kind m_kind;
String m_name;
@ -349,27 +390,6 @@ public:
return num_nullable_member_types;
}
// https://webidl.spec.whatwg.org/#dfn-includes-a-nullable-type
bool includes_nullable_type() const
{
// -> the type is a union type and its number of nullable member types is 1.
return number_of_nullable_member_types() == 1;
}
// -> https://webidl.spec.whatwg.org/#dfn-includes-undefined
bool includes_undefined() const
{
// -> the type is a union type and one of its member types includes undefined.
for (auto& type : m_member_types) {
if (type.is_union() && type.as_union().includes_undefined())
return true;
if (type.name() == "undefined"sv)
return true;
}
return false;
}
private:
NonnullRefPtrVector<Type> m_member_types;
};