Add support for sequences and dictionaries in unions
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Oct 2016 23:31:14 +0000 (23:31 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Oct 2016 23:31:14 +0000 (23:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=163695

Reviewed by Chris Dumez.

Source/WebCore:

Tests:
 - Updated js/dom/webidl-type-mapping.html

* bindings/generic/IDLTypes.h:
Add additional helper predicates and fix formatting.

* bindings/js/JSDOMBinding.h:
Export hasIteratorMethod for use in testing.

* bindings/js/JSDOMConvert.h:
- Change return type of Converter<IDLDictionary<T>> to T, from Optional<T>.
- Add support for unions conversion step 12 (parts 1-3).

* bindings/scripts/CodeGeneratorJS.pm:
(GenerateDefaultValue):
Support complex default value computations for unions using the convert infrastructure.

(GenerateParametersCheck):
(GenerateConstructorDefinition):
Remove incorrect .value() calls now that Converter<IDLDictionary<T>> returns T.

* bindings/scripts/test/JS/JSTestEventConstructor.cpp:
* bindings/scripts/test/JS/JSTestObj.cpp:
Update bindings test results.

* testing/TypeConversions.h:
(WebCore::TypeConversions::setTypeConversionsDictionary):
(WebCore::TypeConversions::typeConversionsDictionaryLongValue):
(WebCore::TypeConversions::typeConversionsDictionaryStringValue):
(WebCore::TypeConversions::typeConversionsDictionarySequenceValue):
(WebCore::TypeConversions::typeConversionsDictionaryUnionType):
* testing/TypeConversions.idl:
Add some complex types to allow testing IDL conversions from tests.

LayoutTests:

* js/dom/webidl-type-mapping-expected.txt:
* js/dom/webidl-type-mapping.html:
Add tests for more complex conversions.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207575 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
LayoutTests/ChangeLog
LayoutTests/js/dom/webidl-type-mapping-expected.txt
LayoutTests/js/dom/webidl-type-mapping.html
Source/WebCore/ChangeLog
Source/WebCore/bindings/generic/IDLTypes.h
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/bindings/js/JSDOMConvert.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
Source/WebCore/testing/TypeConversions.h
Source/WebCore/testing/TypeConversions.idl

index 7e2be61..f0d1fd6 100644 (file)
@@ -1,3 +1,14 @@
+2016-10-19  Sam Weinig  <sam@webkit.org>
+
+        Add support for sequences and dictionaries in unions
+        https://bugs.webkit.org/show_bug.cgi?id=163695
+
+        Reviewed by Chris Dumez.
+
+        * js/dom/webidl-type-mapping-expected.txt:
+        * js/dom/webidl-type-mapping.html:
+        Add tests for more complex conversions.
+
 2016-10-19  Ryan Haddad  <ryanhaddad@apple.com>
 
         Marking platform/mac-wk2/plugins/muted-state.html as failing.
index e042f27..28bea05 100644 (file)
@@ -1059,6 +1059,24 @@ converter.testUSVString = undefined
 converter.testString = undefined
 PASS converter.testUSVString is "undefined"
 PASS converter.testString is "undefined"
+converter.setTypeConversionsDictionary({ longValue: 1 })
+PASS converter.typeConversionsDictionaryLongValue is 1
+converter.setTypeConversionsDictionary({ stringValue: 'hello' })
+PASS converter.typeConversionsDictionaryStringValue is 'hello'
+converter.setTypeConversionsDictionary({ sequenceValue: ['hi', 'there'] })
+PASS converter.typeConversionsDictionarySequenceValue is ['hi', 'there']
+converter.setTypeConversionsDictionary({ unionValue: document })
+PASS converter.typeConversionsDictionaryUnionType is 'node'
+converter.setTypeConversionsDictionary({ unionValue: ['a', 'sequence'] })
+PASS converter.typeConversionsDictionaryUnionType is 'sequence'
+converter.setTypeConversionsDictionary({ unionValue: { longValue: 1 } })
+PASS converter.typeConversionsDictionaryUnionType is 'dictionary'
+converter.setTypeConversionsDictionary({ unionValue: null })
+PASS converter.typeConversionsDictionaryUnionType is 'dictionary'
+converter.setTypeConversionsDictionary({ unionValue: undefined })
+PASS converter.typeConversionsDictionaryUnionType is 'dictionary'
+converter.setTypeConversionsDictionary({ })
+PASS converter.typeConversionsDictionaryUnionType is 'dictionary'
 PASS successfullyParsed is true
 
 TEST COMPLETE
index ca98313..75af49a 100644 (file)
@@ -586,5 +586,25 @@ shouldBeEqualToString("converter.testString", "\u0100");
     shouldBeEqualToString("converter.testString", value);
 });
 
+evalAndLog("converter.setTypeConversionsDictionary({ longValue: 1 })");
+shouldBe("converter.typeConversionsDictionaryLongValue", "1");
+evalAndLog("converter.setTypeConversionsDictionary({ stringValue: 'hello' })");
+shouldBe("converter.typeConversionsDictionaryStringValue", "'hello'");
+evalAndLog("converter.setTypeConversionsDictionary({ sequenceValue: ['hi', 'there'] })");
+shouldBe("converter.typeConversionsDictionarySequenceValue", "['hi', 'there']");
+
+evalAndLog("converter.setTypeConversionsDictionary({ unionValue: document })");
+shouldBe("converter.typeConversionsDictionaryUnionType", "'node'");
+evalAndLog("converter.setTypeConversionsDictionary({ unionValue: ['a', 'sequence'] })");
+shouldBe("converter.typeConversionsDictionaryUnionType", "'sequence'");
+evalAndLog("converter.setTypeConversionsDictionary({ unionValue: { longValue: 1 } })");
+shouldBe("converter.typeConversionsDictionaryUnionType", "'dictionary'");
+evalAndLog("converter.setTypeConversionsDictionary({ unionValue: null })");
+shouldBe("converter.typeConversionsDictionaryUnionType", "'dictionary'");
+evalAndLog("converter.setTypeConversionsDictionary({ unionValue: undefined })");
+shouldBe("converter.typeConversionsDictionaryUnionType", "'dictionary'");
+evalAndLog("converter.setTypeConversionsDictionary({ })");
+shouldBe("converter.typeConversionsDictionaryUnionType", "'dictionary'");
+
 </script>
 <script src="../../resources/js-test-post.js"></script>
index 991b97e..fc1438b 100644 (file)
@@ -1,3 +1,44 @@
+2016-10-19  Sam Weinig  <sam@webkit.org>
+
+        Add support for sequences and dictionaries in unions
+        https://bugs.webkit.org/show_bug.cgi?id=163695
+
+        Reviewed by Chris Dumez.
+
+        Tests:
+         - Updated js/dom/webidl-type-mapping.html
+
+        * bindings/generic/IDLTypes.h:
+        Add additional helper predicates and fix formatting.
+
+        * bindings/js/JSDOMBinding.h:
+        Export hasIteratorMethod for use in testing.
+
+        * bindings/js/JSDOMConvert.h:
+        - Change return type of Converter<IDLDictionary<T>> to T, from Optional<T>.
+        - Add support for unions conversion step 12 (parts 1-3).
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateDefaultValue):
+        Support complex default value computations for unions using the convert infrastructure.
+
+        (GenerateParametersCheck):
+        (GenerateConstructorDefinition):
+        Remove incorrect .value() calls now that Converter<IDLDictionary<T>> returns T.
+
+        * bindings/scripts/test/JS/JSTestEventConstructor.cpp:
+        * bindings/scripts/test/JS/JSTestObj.cpp:
+        Update bindings test results.
+
+        * testing/TypeConversions.h:
+        (WebCore::TypeConversions::setTypeConversionsDictionary):
+        (WebCore::TypeConversions::typeConversionsDictionaryLongValue):
+        (WebCore::TypeConversions::typeConversionsDictionaryStringValue):
+        (WebCore::TypeConversions::typeConversionsDictionarySequenceValue):
+        (WebCore::TypeConversions::typeConversionsDictionaryUnionType):
+        * testing/TypeConversions.idl:
+        Add some complex types to allow testing IDL conversions from tests.
+
 2016-10-19  Ryosuke Niwa  <rniwa@webkit.org>
 
         Annotate more DOM and HTML IDLs with CEReactions
index a0f1877..2c932fe 100644 (file)
@@ -123,16 +123,25 @@ struct IDLBufferSource : IDLType<BufferSource> { };
 
 // Helper predicates
 
-template <typename T>
+template<typename T>
 struct IsIDLInterface : public std::integral_constant<bool, WTF::IsTemplate<T, IDLInterface>::value> { };
 
-template <typename T>
+template<typename T>
 struct IsIDLDictionary : public std::integral_constant<bool, WTF::IsTemplate<T, IDLDictionary>::value> { };
 
-template <typename T>
+template<typename T>
+struct IsIDLEnumeration : public std::integral_constant<bool, WTF::IsTemplate<T, IDLEnumeration>::value> { };
+
+template<typename T>
+struct IsIDLSequence : public std::integral_constant<bool, WTF::IsTemplate<T, IDLSequence>::value> { };
+
+template<typename T>
+struct IsIDLFrozenArray : public std::integral_constant<bool, WTF::IsTemplate<T, IDLFrozenArray>::value> { };
+
+template<typename T>
 struct IsIDLNumber : public std::integral_constant<bool, WTF::IsBaseOfTemplate<IDLNumber, T>::value> { };
 
-template <typename T>
+template<typename T>
 struct IsIDLInteger : public std::integral_constant<bool, WTF::IsBaseOfTemplate<IDLInteger, T>::value> { };
 
 } // namespace WebCore
index 681c8ca..fc3f6ad 100644 (file)
@@ -301,7 +301,7 @@ RefPtr<JSC::Float32Array> toFloat32Array(JSC::JSValue);
 RefPtr<JSC::Float64Array> toFloat64Array(JSC::JSValue);
 
 template<typename T, typename JSType> Vector<Ref<T>> toRefNativeArray(JSC::ExecState&, JSC::JSValue);
-bool hasIteratorMethod(JSC::ExecState&, JSC::JSValue);
+WEBCORE_EXPORT bool hasIteratorMethod(JSC::ExecState&, JSC::JSValue);
 
 bool shouldAllowAccessToNode(JSC::ExecState*, Node*);
 bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*);
index 11a947d..6ecd31f 100644 (file)
@@ -408,7 +408,7 @@ template<typename T> struct Converter<IDLFrozenArray<T>> : DefaultConverter<IDLF
 // MARK: Dictionary type
 
 template<typename T> struct Converter<IDLDictionary<T>> : DefaultConverter<IDLDictionary<T>> {
-    using ReturnType = Optional<T>;
+    using ReturnType = T;
 
     static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
     {
@@ -476,17 +476,33 @@ struct Converter<IDLUnion<T...>> : DefaultConverter<IDLUnion<T...>>
     using TypeList = typename Type::TypeList;
     using ReturnType = typename Type::ImplementationType;
 
-    using DictionaryTypeList = brigand::find<TypeList, IsIDLDictionary<brigand::_1>>;
-    using DictionaryType = ConditionalFront<DictionaryTypeList, brigand::size<DictionaryTypeList>::value != 0>;
-    static_assert(brigand::size<DictionaryTypeList>::value == 0 || brigand::size<DictionaryTypeList>::value == 1, "There can be 0 or 1 dictionary types in an IDLUnion.");
+    using NumericTypeList = brigand::filter<TypeList, IsIDLNumber<brigand::_1>>;
+    static constexpr size_t numberOfNumericTypes = brigand::size<NumericTypeList>::value;
+    static_assert(numberOfNumericTypes == 0 || numberOfNumericTypes == 1, "There can be 0 or 1 numeric types in an IDLUnion.");
+    using NumericType = ConditionalFront<NumericTypeList, numberOfNumericTypes != 0>;
 
-    using NumericTypeList = brigand::find<TypeList, IsIDLNumber<brigand::_1>>;
-    using NumericType = ConditionalFront<NumericTypeList, brigand::size<NumericTypeList>::value != 0>;
-    static_assert(brigand::size<NumericTypeList>::value == 0 || brigand::size<NumericTypeList>::value == 1, "There can be 0 or 1 numeric types in an IDLUnion.");
+    // FIXME: This should also check for IDLEnumeration<T>.
+    using StringTypeList = brigand::filter<TypeList, std::is_base_of<IDLString, brigand::_1>>;
+    static constexpr size_t numberOfStringTypes = brigand::size<StringTypeList>::value;
+    static_assert(numberOfStringTypes == 0 || numberOfStringTypes == 1, "There can be 0 or 1 string types in an IDLUnion.");
+    using StringType = ConditionalFront<StringTypeList, numberOfStringTypes != 0>;
 
-    using StringTypeList = brigand::find<TypeList, std::is_base_of<IDLString, brigand::_1>>;
-    using StringType = ConditionalFront<StringTypeList, brigand::size<StringTypeList>::value != 0>;
-    static_assert(brigand::size<StringTypeList>::value == 0 || brigand::size<StringTypeList>::value == 1, "There can be 0 or 1 string types in an IDLUnion.");
+    using SequenceTypeList = brigand::filter<TypeList, IsIDLSequence<brigand::_1>>;
+    static constexpr size_t numberOfSequenceTypes = brigand::size<SequenceTypeList>::value;
+    static_assert(numberOfSequenceTypes == 0 || numberOfSequenceTypes == 1, "There can be 0 or 1 sequence types in an IDLUnion.");
+    using SequenceType = ConditionalFront<SequenceTypeList, numberOfSequenceTypes != 0>;
+
+    using FrozenArrayTypeList = brigand::filter<TypeList, IsIDLFrozenArray<brigand::_1>>;
+    static constexpr size_t numberOfFrozenArrayTypes = brigand::size<FrozenArrayTypeList>::value;
+    static_assert(numberOfFrozenArrayTypes == 0 || numberOfFrozenArrayTypes == 1, "There can be 0 or 1 FrozenArray types in an IDLUnion.");
+    using FrozenArrayType = ConditionalFront<FrozenArrayTypeList, numberOfFrozenArrayTypes != 0>;
+
+    using DictionaryTypeList = brigand::filter<TypeList, IsIDLDictionary<brigand::_1>>;
+    static constexpr size_t numberOfDictionaryTypes = brigand::size<DictionaryTypeList>::value;
+    static_assert(numberOfDictionaryTypes == 0 || numberOfDictionaryTypes == 1, "There can be 0 or 1 dictionary types in an IDLUnion.");
+    using DictionaryType = ConditionalFront<DictionaryTypeList, numberOfDictionaryTypes != 0>;
+
+    static constexpr bool hasObjectType = (numberOfSequenceTypes + numberOfFrozenArrayTypes + numberOfDictionaryTypes) > 0;
 
     using InterfaceTypeList = brigand::filter<TypeList, IsIDLInterface<brigand::_1>>;
 
@@ -505,7 +521,7 @@ struct Converter<IDLUnion<T...>> : DefaultConverter<IDLUnion<T...>>
         // NOTE: Union is expected to be pre-flattented.
         
         // 3. If V is null or undefined, and types includes a dictionary type, then return the result of converting V to that dictionary type.
-        constexpr bool hasDictionaryType = brigand::size<DictionaryTypeList>::value != 0;
+        constexpr bool hasDictionaryType = numberOfDictionaryTypes != 0;
         if (hasDictionaryType) {
             if (value.isUndefinedOrNull())
                 return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, DictionaryType, hasDictionaryType>::convert(state, value).value());
@@ -535,8 +551,57 @@ struct Converter<IDLUnion<T...>> : DefaultConverter<IDLUnion<T...>>
                 return WTFMove(returnValue.value());
         }
         
-        // FIXME: Add support for steps 5 - 12.
-        
+        // FIXME: Add support for steps 5 - 11.
+
+        // 12. If V is any kind of object except for a native RegExp object, then:
+        if (hasObjectType) {
+            if (value.isCell()) {
+                JSC::JSCell* cell = value.asCell();
+                if (cell->isObject() && cell->type() != JSC::RegExpObjectType) {
+                    // FIXME: We should be able to optimize the following code by making use
+                    // of the fact that we have proved that the value is an object. 
+                
+                    //     1. If types includes a sequence type, then:
+                    //         1. Let method be the result of GetMethod(V, @@iterator).
+                    //         2. ReturnIfAbrupt(method).
+                    //         3. If method is not undefined, return the result of creating a
+                    //            sequence of that type from V and method.        
+                    constexpr bool hasSequenceType = numberOfSequenceTypes != 0;
+                    if (hasSequenceType) {
+                        bool hasIterator = hasIteratorMethod(state, value);
+                        RETURN_IF_EXCEPTION(scope, ReturnType());
+                        if (hasIterator)
+                            return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, SequenceType, hasSequenceType>::convert(state, value).value());
+                    }
+
+                    //     2. If types includes a frozen array type, then:
+                    //         1. Let method be the result of GetMethod(V, @@iterator).
+                    //         2. ReturnIfAbrupt(method).
+                    //         3. If method is not undefined, return the result of creating a
+                    //            frozen array of that type from V and method.
+                    constexpr bool hasFrozenArrayType = numberOfFrozenArrayTypes != 0;
+                    if (hasFrozenArrayType) {
+                        bool hasIterator = hasIteratorMethod(state, value);
+                        RETURN_IF_EXCEPTION(scope, ReturnType());
+                        if (hasIterator)
+                            return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, FrozenArrayType, hasFrozenArrayType>::convert(state, value).value());
+                    }
+
+                    //     3. If types includes a dictionary type, then return the result of
+                    //        converting V to that dictionary type.
+                    if (hasDictionaryType)
+                        return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, DictionaryType, hasDictionaryType>::convert(state, value).value());
+
+                    //     4. If types includes a record type, then return the result of converting V to that record type.
+                    //         (FIXME: Add support for record types and step 12.4)
+                    //     5. If types includes a callback interface type, then return the result of converting V to that interface type.
+                    //         (FIXME: Add support for callback interface type and step 12.5)
+                    //     6. If types includes object, then return the IDL value that is a reference to the object V.
+                    //         (FIXME: Add support for object and step 12.6)
+                }
+            }
+        }
+
         // 13. If V is a Boolean value, then:
         //     1. If types includes a boolean, then return the result of converting V to boolean.
         constexpr bool hasBooleanType = brigand::any<TypeList, std::is_same<IDLBoolean, brigand::_1>>::value;
index 6d659eb..e17ace3 100644 (file)
@@ -1008,7 +1008,12 @@ sub GenerateDefaultValue
         return $className . "::" . $enumerationValueName;
     }
     if ($defaultValue eq "null") {
-        return "Nullopt" if $signature->idlType->isUnion;
+        if ($signature->idlType->isUnion) {
+            return "Nullopt" if $signature->idlType->isNullable;
+
+            my $IDLType = GetIDLType($interface, $signature->idlType);
+            return "convert<${IDLType}>(state, jsNull());";
+        }
         return "jsNull()" if $signature->type eq "any";
         return "nullptr" if $codeGenerator->IsWrapperType($signature->type) || $codeGenerator->IsTypedArrayType($signature->type);
         return "String()" if $codeGenerator->IsStringType($signature->type);
@@ -4364,7 +4369,7 @@ sub GenerateParametersCheck
             if ($codeGenerator->IsTypedArrayType($type) and $parameter->type ne "ArrayBuffer") {
                $value = $shouldPassByReference ? "$name.releaseNonNull()" : "WTFMove($name)";
             } elsif ($codeGenerator->IsDictionaryType($type)) {
-                $value = "${name}.value()";
+                $value = "${name}";
             }
         }
 
@@ -5763,7 +5768,7 @@ sub GenerateConstructorDefinition
                 if (ShouldPassWrapperByReference($parameter, $interface)) {
                     push(@constructorArgList, "*" . $parameter->name);
                 } elsif ($codeGenerator->IsDictionaryType($parameter->type)) {
-                    push(@constructorArgList, $parameter->name . ".value()");
+                    push(@constructorArgList, $parameter->name);
                 } else {
                     push(@constructorArgList, "WTFMove(" . $parameter->name . ")");
                 }
index 402c5ec..1a7dd37 100644 (file)
@@ -131,7 +131,7 @@ template<> EncodedJSValue JSC_HOST_CALL JSTestEventConstructorConstructor::const
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
     auto eventInitDict = convert<IDLDictionary<TestEventConstructor::Init>>(*state, state->argument(1));
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-    auto object = TestEventConstructor::create(WTFMove(type), eventInitDict.value());
+    auto object = TestEventConstructor::create(WTFMove(type), eventInitDict);
     return JSValue::encode(toJSNewlyCreated(state, castedThis->globalObject(), WTFMove(object)));
 }
 
index f9c5f72..c827eae 100644 (file)
@@ -7710,7 +7710,7 @@ static inline JSC::EncodedJSValue jsTestObjPrototypeFunctionAttachShadowRootCall
         return throwVMError(state, throwScope, createNotEnoughArgumentsError(state));
     auto init = convert<IDLDictionary<TestObj::Dictionary>>(*state, state->uncheckedArgument(0));
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-    impl.attachShadowRoot(init.value());
+    impl.attachShadowRoot(init);
     return JSValue::encode(jsUndefined());
 }
 
@@ -7730,7 +7730,7 @@ static inline JSC::EncodedJSValue jsTestObjPrototypeFunctionOperationWithExterna
         return throwVMError(state, throwScope, createNotEnoughArgumentsError(state));
     auto dict = convert<IDLDictionary<DictionaryImplName>>(*state, state->uncheckedArgument(0));
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-    impl.operationWithExternalDictionaryParameter(dict.value());
+    impl.operationWithExternalDictionaryParameter(dict);
     return JSValue::encode(jsUndefined());
 }
 
index f1882f8..14bb151 100644 (file)
 #ifndef TypeConversions_h
 #define TypeConversions_h
 
+#include "Node.h"
 #include <wtf/FastMalloc.h>
 #include <wtf/RefCounted.h>
+#include <wtf/Variant.h>
+#include <wtf/Vector.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -36,6 +39,24 @@ class TypeConversions : public RefCounted<TypeConversions> {
 public:
     static Ref<TypeConversions> create() { return adoptRef(*new TypeConversions()); }
 
+    enum class UnionType {
+        Node,
+        Sequence,
+        Dictionary
+    };
+
+    struct OtherDictionary {
+        int longValue;
+        String stringValue;
+    };
+
+    struct Dictionary {
+        int longValue;
+        String stringValue;
+        Vector<String> sequenceValue;
+        Variant<RefPtr<Node>, Vector<String>, OtherDictionary> unionValue;
+    };
+
     long testLong() { return m_long; }
     void setTestLong(long value) { m_long = value; }
     long testEnforceRangeLong() { return m_long; }
@@ -77,21 +98,46 @@ public:
     const String& testUSVString() const { return m_usvstring; }
     void setTestUSVString(const String& usvstring) { m_usvstring = usvstring; }
 
+    void setTypeConversionsDictionary(Dictionary& dictionary)
+    {
+        m_typeConversionsDictionaryLongValue = dictionary.longValue;
+        m_typeConversionsDictionaryStringValue = dictionary.stringValue;
+        m_typeConversionsDictionarySequenceValue = dictionary.sequenceValue;
+        m_typeConversionsDictionaryUnionValue = dictionary.unionValue;
+    }
+
+    int typeConversionsDictionaryLongValue() { return m_typeConversionsDictionaryLongValue; }
+    String typeConversionsDictionaryStringValue() { return m_typeConversionsDictionaryStringValue; }
+    Vector<String> typeConversionsDictionarySequenceValue() { return m_typeConversionsDictionarySequenceValue; }
+    UnionType typeConversionsDictionaryUnionType()
+    {
+        return WTF::visit(WTF::makeVisitor(
+            [](const RefPtr<Node>&) -> UnionType { return UnionType::Node; },
+            [](const Vector<String>&) -> UnionType { return UnionType::Sequence; },
+            [](const OtherDictionary&) -> UnionType { return UnionType::Dictionary; }
+        ), m_typeConversionsDictionaryUnionValue);
+    }
+
 private:
     TypeConversions()
     {
     }
 
-    long m_long;
-    unsigned long m_unsignedLong;
-    long long m_longLong;
-    unsigned long long m_unsignedLongLong;
-    int8_t m_byte;
-    uint8_t m_octet;
-    int16_t m_short;
-    uint16_t m_UnsignedShort;
+    long m_long { 0 };
+    unsigned long m_unsignedLong { 0 };
+    long long m_longLong { 0 };
+    unsigned long long m_unsignedLongLong { 0 };
+    int8_t m_byte { 0 };
+    uint8_t m_octet { 0 };
+    int16_t m_short { 0 };
+    uint16_t m_UnsignedShort { 0 };
     String m_string;
     String m_usvstring;
+    
+    int m_typeConversionsDictionaryLongValue { 0 };
+    String m_typeConversionsDictionaryStringValue;
+    Vector<String> m_typeConversionsDictionarySequenceValue;
+    Variant<RefPtr<Node>, Vector<String>, OtherDictionary> m_typeConversionsDictionaryUnionValue;
 };
 
 } // namespace WebCore
index ac6241a..e0f9b4d 100644 (file)
@@ -23,6 +23,8 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+enum UnionType { "node", "sequence", "dictionary" };
+
 [
     NoInterfaceObject,
     ImplementationLacksVTable,
 
     attribute DOMString testString;
     attribute USVString testUSVString;
+    
+    void setTypeConversionsDictionary(TypeConversionsDictionary d);
+    readonly attribute long typeConversionsDictionaryLongValue;
+    readonly attribute DOMString typeConversionsDictionaryStringValue;
+    readonly attribute sequence<DOMString> typeConversionsDictionarySequenceValue;
+    readonly attribute UnionType typeConversionsDictionaryUnionType; 
+};
+
+dictionary TypeConversionsOtherDictionary {
+    long longValue = 0;
+    DOMString stringValue = "";
+};
+
+dictionary TypeConversionsDictionary {
+    long longValue = 0;
+    DOMString stringValue = "";
+    sequence<DOMString> sequenceValue = [];
+    (Node or sequence<DOMString> or TypeConversionsOtherDictionary) unionValue = null;
 };