Changeset 207575 in webkit


Ignore:
Timestamp:
Oct 19, 2016 4:31:14 PM (7 years ago)
Author:
weinig@apple.com
Message:

Add support for sequences and dictionaries in unions
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.

Location:
trunk
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r207574 r207575  
     12016-10-19  Sam Weinig  <sam@webkit.org>
     2
     3        Add support for sequences and dictionaries in unions
     4        https://bugs.webkit.org/show_bug.cgi?id=163695
     5
     6        Reviewed by Chris Dumez.
     7
     8        * js/dom/webidl-type-mapping-expected.txt:
     9        * js/dom/webidl-type-mapping.html:
     10        Add tests for more complex conversions.
     11
    1122016-10-19  Ryan Haddad  <ryanhaddad@apple.com>
    213
  • trunk/LayoutTests/js/dom/webidl-type-mapping-expected.txt

    r204215 r207575  
    10601060PASS converter.testUSVString is "undefined"
    10611061PASS converter.testString is "undefined"
     1062converter.setTypeConversionsDictionary({ longValue: 1 })
     1063PASS converter.typeConversionsDictionaryLongValue is 1
     1064converter.setTypeConversionsDictionary({ stringValue: 'hello' })
     1065PASS converter.typeConversionsDictionaryStringValue is 'hello'
     1066converter.setTypeConversionsDictionary({ sequenceValue: ['hi', 'there'] })
     1067PASS converter.typeConversionsDictionarySequenceValue is ['hi', 'there']
     1068converter.setTypeConversionsDictionary({ unionValue: document })
     1069PASS converter.typeConversionsDictionaryUnionType is 'node'
     1070converter.setTypeConversionsDictionary({ unionValue: ['a', 'sequence'] })
     1071PASS converter.typeConversionsDictionaryUnionType is 'sequence'
     1072converter.setTypeConversionsDictionary({ unionValue: { longValue: 1 } })
     1073PASS converter.typeConversionsDictionaryUnionType is 'dictionary'
     1074converter.setTypeConversionsDictionary({ unionValue: null })
     1075PASS converter.typeConversionsDictionaryUnionType is 'dictionary'
     1076converter.setTypeConversionsDictionary({ unionValue: undefined })
     1077PASS converter.typeConversionsDictionaryUnionType is 'dictionary'
     1078converter.setTypeConversionsDictionary({ })
     1079PASS converter.typeConversionsDictionaryUnionType is 'dictionary'
    10621080PASS successfullyParsed is true
    10631081
  • trunk/LayoutTests/js/dom/webidl-type-mapping.html

    r204215 r207575  
    587587});
    588588
     589evalAndLog("converter.setTypeConversionsDictionary({ longValue: 1 })");
     590shouldBe("converter.typeConversionsDictionaryLongValue", "1");
     591evalAndLog("converter.setTypeConversionsDictionary({ stringValue: 'hello' })");
     592shouldBe("converter.typeConversionsDictionaryStringValue", "'hello'");
     593evalAndLog("converter.setTypeConversionsDictionary({ sequenceValue: ['hi', 'there'] })");
     594shouldBe("converter.typeConversionsDictionarySequenceValue", "['hi', 'there']");
     595
     596evalAndLog("converter.setTypeConversionsDictionary({ unionValue: document })");
     597shouldBe("converter.typeConversionsDictionaryUnionType", "'node'");
     598evalAndLog("converter.setTypeConversionsDictionary({ unionValue: ['a', 'sequence'] })");
     599shouldBe("converter.typeConversionsDictionaryUnionType", "'sequence'");
     600evalAndLog("converter.setTypeConversionsDictionary({ unionValue: { longValue: 1 } })");
     601shouldBe("converter.typeConversionsDictionaryUnionType", "'dictionary'");
     602evalAndLog("converter.setTypeConversionsDictionary({ unionValue: null })");
     603shouldBe("converter.typeConversionsDictionaryUnionType", "'dictionary'");
     604evalAndLog("converter.setTypeConversionsDictionary({ unionValue: undefined })");
     605shouldBe("converter.typeConversionsDictionaryUnionType", "'dictionary'");
     606evalAndLog("converter.setTypeConversionsDictionary({ })");
     607shouldBe("converter.typeConversionsDictionaryUnionType", "'dictionary'");
     608
    589609</script>
    590610<script src="../../resources/js-test-post.js"></script>
  • trunk/Source/WebCore/ChangeLog

    r207571 r207575  
     12016-10-19  Sam Weinig  <sam@webkit.org>
     2
     3        Add support for sequences and dictionaries in unions
     4        https://bugs.webkit.org/show_bug.cgi?id=163695
     5
     6        Reviewed by Chris Dumez.
     7
     8        Tests:
     9         - Updated js/dom/webidl-type-mapping.html
     10
     11        * bindings/generic/IDLTypes.h:
     12        Add additional helper predicates and fix formatting.
     13
     14        * bindings/js/JSDOMBinding.h:
     15        Export hasIteratorMethod for use in testing.
     16
     17        * bindings/js/JSDOMConvert.h:
     18        - Change return type of Converter<IDLDictionary<T>> to T, from Optional<T>.
     19        - Add support for unions conversion step 12 (parts 1-3).
     20
     21        * bindings/scripts/CodeGeneratorJS.pm:
     22        (GenerateDefaultValue):
     23        Support complex default value computations for unions using the convert infrastructure.
     24
     25        (GenerateParametersCheck):
     26        (GenerateConstructorDefinition):
     27        Remove incorrect .value() calls now that Converter<IDLDictionary<T>> returns T.
     28
     29        * bindings/scripts/test/JS/JSTestEventConstructor.cpp:
     30        * bindings/scripts/test/JS/JSTestObj.cpp:
     31        Update bindings test results.
     32
     33        * testing/TypeConversions.h:
     34        (WebCore::TypeConversions::setTypeConversionsDictionary):
     35        (WebCore::TypeConversions::typeConversionsDictionaryLongValue):
     36        (WebCore::TypeConversions::typeConversionsDictionaryStringValue):
     37        (WebCore::TypeConversions::typeConversionsDictionarySequenceValue):
     38        (WebCore::TypeConversions::typeConversionsDictionaryUnionType):
     39        * testing/TypeConversions.idl:
     40        Add some complex types to allow testing IDL conversions from tests.
     41
    1422016-10-19  Ryosuke Niwa  <rniwa@webkit.org>
    243
  • trunk/Source/WebCore/bindings/generic/IDLTypes.h

    r207517 r207575  
    124124// Helper predicates
    125125
    126 template <typename T>
     126template<typename T>
    127127struct IsIDLInterface : public std::integral_constant<bool, WTF::IsTemplate<T, IDLInterface>::value> { };
    128128
    129 template <typename T>
     129template<typename T>
    130130struct IsIDLDictionary : public std::integral_constant<bool, WTF::IsTemplate<T, IDLDictionary>::value> { };
    131131
    132 template <typename T>
     132template<typename T>
     133struct IsIDLEnumeration : public std::integral_constant<bool, WTF::IsTemplate<T, IDLEnumeration>::value> { };
     134
     135template<typename T>
     136struct IsIDLSequence : public std::integral_constant<bool, WTF::IsTemplate<T, IDLSequence>::value> { };
     137
     138template<typename T>
     139struct IsIDLFrozenArray : public std::integral_constant<bool, WTF::IsTemplate<T, IDLFrozenArray>::value> { };
     140
     141template<typename T>
    133142struct IsIDLNumber : public std::integral_constant<bool, WTF::IsBaseOfTemplate<IDLNumber, T>::value> { };
    134143
    135 template <typename T>
     144template<typename T>
    136145struct IsIDLInteger : public std::integral_constant<bool, WTF::IsBaseOfTemplate<IDLInteger, T>::value> { };
    137146
  • trunk/Source/WebCore/bindings/js/JSDOMBinding.h

    r207521 r207575  
    302302
    303303template<typename T, typename JSType> Vector<Ref<T>> toRefNativeArray(JSC::ExecState&, JSC::JSValue);
    304 bool hasIteratorMethod(JSC::ExecState&, JSC::JSValue);
     304WEBCORE_EXPORT bool hasIteratorMethod(JSC::ExecState&, JSC::JSValue);
    305305
    306306bool shouldAllowAccessToNode(JSC::ExecState*, Node*);
  • trunk/Source/WebCore/bindings/js/JSDOMConvert.h

    r207498 r207575  
    409409
    410410template<typename T> struct Converter<IDLDictionary<T>> : DefaultConverter<IDLDictionary<T>> {
    411     using ReturnType = Optional<T>;
     411    using ReturnType = T;
    412412
    413413    static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
     
    477477    using ReturnType = typename Type::ImplementationType;
    478478
    479     using DictionaryTypeList = brigand::find<TypeList, IsIDLDictionary<brigand::_1>>;
    480     using DictionaryType = ConditionalFront<DictionaryTypeList, brigand::size<DictionaryTypeList>::value != 0>;
    481     static_assert(brigand::size<DictionaryTypeList>::value == 0 || brigand::size<DictionaryTypeList>::value == 1, "There can be 0 or 1 dictionary types in an IDLUnion.");
    482 
    483     using NumericTypeList = brigand::find<TypeList, IsIDLNumber<brigand::_1>>;
    484     using NumericType = ConditionalFront<NumericTypeList, brigand::size<NumericTypeList>::value != 0>;
    485     static_assert(brigand::size<NumericTypeList>::value == 0 || brigand::size<NumericTypeList>::value == 1, "There can be 0 or 1 numeric types in an IDLUnion.");
    486 
    487     using StringTypeList = brigand::find<TypeList, std::is_base_of<IDLString, brigand::_1>>;
    488     using StringType = ConditionalFront<StringTypeList, brigand::size<StringTypeList>::value != 0>;
    489     static_assert(brigand::size<StringTypeList>::value == 0 || brigand::size<StringTypeList>::value == 1, "There can be 0 or 1 string types in an IDLUnion.");
     479    using NumericTypeList = brigand::filter<TypeList, IsIDLNumber<brigand::_1>>;
     480    static constexpr size_t numberOfNumericTypes = brigand::size<NumericTypeList>::value;
     481    static_assert(numberOfNumericTypes == 0 || numberOfNumericTypes == 1, "There can be 0 or 1 numeric types in an IDLUnion.");
     482    using NumericType = ConditionalFront<NumericTypeList, numberOfNumericTypes != 0>;
     483
     484    // FIXME: This should also check for IDLEnumeration<T>.
     485    using StringTypeList = brigand::filter<TypeList, std::is_base_of<IDLString, brigand::_1>>;
     486    static constexpr size_t numberOfStringTypes = brigand::size<StringTypeList>::value;
     487    static_assert(numberOfStringTypes == 0 || numberOfStringTypes == 1, "There can be 0 or 1 string types in an IDLUnion.");
     488    using StringType = ConditionalFront<StringTypeList, numberOfStringTypes != 0>;
     489
     490    using SequenceTypeList = brigand::filter<TypeList, IsIDLSequence<brigand::_1>>;
     491    static constexpr size_t numberOfSequenceTypes = brigand::size<SequenceTypeList>::value;
     492    static_assert(numberOfSequenceTypes == 0 || numberOfSequenceTypes == 1, "There can be 0 or 1 sequence types in an IDLUnion.");
     493    using SequenceType = ConditionalFront<SequenceTypeList, numberOfSequenceTypes != 0>;
     494
     495    using FrozenArrayTypeList = brigand::filter<TypeList, IsIDLFrozenArray<brigand::_1>>;
     496    static constexpr size_t numberOfFrozenArrayTypes = brigand::size<FrozenArrayTypeList>::value;
     497    static_assert(numberOfFrozenArrayTypes == 0 || numberOfFrozenArrayTypes == 1, "There can be 0 or 1 FrozenArray types in an IDLUnion.");
     498    using FrozenArrayType = ConditionalFront<FrozenArrayTypeList, numberOfFrozenArrayTypes != 0>;
     499
     500    using DictionaryTypeList = brigand::filter<TypeList, IsIDLDictionary<brigand::_1>>;
     501    static constexpr size_t numberOfDictionaryTypes = brigand::size<DictionaryTypeList>::value;
     502    static_assert(numberOfDictionaryTypes == 0 || numberOfDictionaryTypes == 1, "There can be 0 or 1 dictionary types in an IDLUnion.");
     503    using DictionaryType = ConditionalFront<DictionaryTypeList, numberOfDictionaryTypes != 0>;
     504
     505    static constexpr bool hasObjectType = (numberOfSequenceTypes + numberOfFrozenArrayTypes + numberOfDictionaryTypes) > 0;
    490506
    491507    using InterfaceTypeList = brigand::filter<TypeList, IsIDLInterface<brigand::_1>>;
     
    506522       
    507523        // 3. If V is null or undefined, and types includes a dictionary type, then return the result of converting V to that dictionary type.
    508         constexpr bool hasDictionaryType = brigand::size<DictionaryTypeList>::value != 0;
     524        constexpr bool hasDictionaryType = numberOfDictionaryTypes != 0;
    509525        if (hasDictionaryType) {
    510526            if (value.isUndefinedOrNull())
     
    536552        }
    537553       
    538         // FIXME: Add support for steps 5 - 12.
    539        
     554        // FIXME: Add support for steps 5 - 11.
     555
     556        // 12. If V is any kind of object except for a native RegExp object, then:
     557        if (hasObjectType) {
     558            if (value.isCell()) {
     559                JSC::JSCell* cell = value.asCell();
     560                if (cell->isObject() && cell->type() != JSC::RegExpObjectType) {
     561                    // FIXME: We should be able to optimize the following code by making use
     562                    // of the fact that we have proved that the value is an object.
     563               
     564                    //     1. If types includes a sequence type, then:
     565                    //         1. Let method be the result of GetMethod(V, @@iterator).
     566                    //         2. ReturnIfAbrupt(method).
     567                    //         3. If method is not undefined, return the result of creating a
     568                    //            sequence of that type from V and method.       
     569                    constexpr bool hasSequenceType = numberOfSequenceTypes != 0;
     570                    if (hasSequenceType) {
     571                        bool hasIterator = hasIteratorMethod(state, value);
     572                        RETURN_IF_EXCEPTION(scope, ReturnType());
     573                        if (hasIterator)
     574                            return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, SequenceType, hasSequenceType>::convert(state, value).value());
     575                    }
     576
     577                    //     2. If types includes a frozen array type, then:
     578                    //         1. Let method be the result of GetMethod(V, @@iterator).
     579                    //         2. ReturnIfAbrupt(method).
     580                    //         3. If method is not undefined, return the result of creating a
     581                    //            frozen array of that type from V and method.
     582                    constexpr bool hasFrozenArrayType = numberOfFrozenArrayTypes != 0;
     583                    if (hasFrozenArrayType) {
     584                        bool hasIterator = hasIteratorMethod(state, value);
     585                        RETURN_IF_EXCEPTION(scope, ReturnType());
     586                        if (hasIterator)
     587                            return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, FrozenArrayType, hasFrozenArrayType>::convert(state, value).value());
     588                    }
     589
     590                    //     3. If types includes a dictionary type, then return the result of
     591                    //        converting V to that dictionary type.
     592                    if (hasDictionaryType)
     593                        return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, DictionaryType, hasDictionaryType>::convert(state, value).value());
     594
     595                    //     4. If types includes a record type, then return the result of converting V to that record type.
     596                    //         (FIXME: Add support for record types and step 12.4)
     597                    //     5. If types includes a callback interface type, then return the result of converting V to that interface type.
     598                    //         (FIXME: Add support for callback interface type and step 12.5)
     599                    //     6. If types includes object, then return the IDL value that is a reference to the object V.
     600                    //         (FIXME: Add support for object and step 12.6)
     601                }
     602            }
     603        }
     604
    540605        // 13. If V is a Boolean value, then:
    541606        //     1. If types includes a boolean, then return the result of converting V to boolean.
  • trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm

    r207521 r207575  
    10091009    }
    10101010    if ($defaultValue eq "null") {
    1011         return "Nullopt" if $signature->idlType->isUnion;
     1011        if ($signature->idlType->isUnion) {
     1012            return "Nullopt" if $signature->idlType->isNullable;
     1013
     1014            my $IDLType = GetIDLType($interface, $signature->idlType);
     1015            return "convert<${IDLType}>(state, jsNull());";
     1016        }
    10121017        return "jsNull()" if $signature->type eq "any";
    10131018        return "nullptr" if $codeGenerator->IsWrapperType($signature->type) || $codeGenerator->IsTypedArrayType($signature->type);
     
    43654370               $value = $shouldPassByReference ? "$name.releaseNonNull()" : "WTFMove($name)";
    43664371            } elsif ($codeGenerator->IsDictionaryType($type)) {
    4367                 $value = "${name}.value()";
     4372                $value = "${name}";
    43684373            }
    43694374        }
     
    57645769                    push(@constructorArgList, "*" . $parameter->name);
    57655770                } elsif ($codeGenerator->IsDictionaryType($parameter->type)) {
    5766                     push(@constructorArgList, $parameter->name . ".value()");
     5771                    push(@constructorArgList, $parameter->name);
    57675772                } else {
    57685773                    push(@constructorArgList, "WTFMove(" . $parameter->name . ")");
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp

    r207498 r207575  
    132132    auto eventInitDict = convert<IDLDictionary<TestEventConstructor::Init>>(*state, state->argument(1));
    133133    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
    134     auto object = TestEventConstructor::create(WTFMove(type), eventInitDict.value());
     134    auto object = TestEventConstructor::create(WTFMove(type), eventInitDict);
    135135    return JSValue::encode(toJSNewlyCreated(state, castedThis->globalObject(), WTFMove(object)));
    136136}
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp

    r207519 r207575  
    77117711    auto init = convert<IDLDictionary<TestObj::Dictionary>>(*state, state->uncheckedArgument(0));
    77127712    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
    7713     impl.attachShadowRoot(init.value());
     7713    impl.attachShadowRoot(init);
    77147714    return JSValue::encode(jsUndefined());
    77157715}
     
    77317731    auto dict = convert<IDLDictionary<DictionaryImplName>>(*state, state->uncheckedArgument(0));
    77327732    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
    7733     impl.operationWithExternalDictionaryParameter(dict.value());
     7733    impl.operationWithExternalDictionaryParameter(dict);
    77347734    return JSValue::encode(jsUndefined());
    77357735}
  • trunk/Source/WebCore/testing/TypeConversions.h

    r204215 r207575  
    2727#define TypeConversions_h
    2828
     29#include "Node.h"
    2930#include <wtf/FastMalloc.h>
    3031#include <wtf/RefCounted.h>
     32#include <wtf/Variant.h>
     33#include <wtf/Vector.h>
    3134#include <wtf/text/WTFString.h>
    3235
     
    3639public:
    3740    static Ref<TypeConversions> create() { return adoptRef(*new TypeConversions()); }
     41
     42    enum class UnionType {
     43        Node,
     44        Sequence,
     45        Dictionary
     46    };
     47
     48    struct OtherDictionary {
     49        int longValue;
     50        String stringValue;
     51    };
     52
     53    struct Dictionary {
     54        int longValue;
     55        String stringValue;
     56        Vector<String> sequenceValue;
     57        Variant<RefPtr<Node>, Vector<String>, OtherDictionary> unionValue;
     58    };
    3859
    3960    long testLong() { return m_long; }
     
    7899    void setTestUSVString(const String& usvstring) { m_usvstring = usvstring; }
    79100
     101    void setTypeConversionsDictionary(Dictionary& dictionary)
     102    {
     103        m_typeConversionsDictionaryLongValue = dictionary.longValue;
     104        m_typeConversionsDictionaryStringValue = dictionary.stringValue;
     105        m_typeConversionsDictionarySequenceValue = dictionary.sequenceValue;
     106        m_typeConversionsDictionaryUnionValue = dictionary.unionValue;
     107    }
     108
     109    int typeConversionsDictionaryLongValue() { return m_typeConversionsDictionaryLongValue; }
     110    String typeConversionsDictionaryStringValue() { return m_typeConversionsDictionaryStringValue; }
     111    Vector<String> typeConversionsDictionarySequenceValue() { return m_typeConversionsDictionarySequenceValue; }
     112    UnionType typeConversionsDictionaryUnionType()
     113    {
     114        return WTF::visit(WTF::makeVisitor(
     115            [](const RefPtr<Node>&) -> UnionType { return UnionType::Node; },
     116            [](const Vector<String>&) -> UnionType { return UnionType::Sequence; },
     117            [](const OtherDictionary&) -> UnionType { return UnionType::Dictionary; }
     118        ), m_typeConversionsDictionaryUnionValue);
     119    }
     120
    80121private:
    81122    TypeConversions()
     
    83124    }
    84125
    85     long m_long;
    86     unsigned long m_unsignedLong;
    87     long long m_longLong;
    88     unsigned long long m_unsignedLongLong;
    89     int8_t m_byte;
    90     uint8_t m_octet;
    91     int16_t m_short;
    92     uint16_t m_UnsignedShort;
     126    long m_long { 0 };
     127    unsigned long m_unsignedLong { 0 };
     128    long long m_longLong { 0 };
     129    unsigned long long m_unsignedLongLong { 0 };
     130    int8_t m_byte { 0 };
     131    uint8_t m_octet { 0 };
     132    int16_t m_short { 0 };
     133    uint16_t m_UnsignedShort { 0 };
    93134    String m_string;
    94135    String m_usvstring;
     136   
     137    int m_typeConversionsDictionaryLongValue { 0 };
     138    String m_typeConversionsDictionaryStringValue;
     139    Vector<String> m_typeConversionsDictionarySequenceValue;
     140    Variant<RefPtr<Node>, Vector<String>, OtherDictionary> m_typeConversionsDictionaryUnionValue;
    95141};
    96142
  • trunk/Source/WebCore/testing/TypeConversions.idl

    r204215 r207575  
    2323 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2424 */
     25
     26enum UnionType { "node", "sequence", "dictionary" };
    2527
    2628[
     
    5153    attribute DOMString testString;
    5254    attribute USVString testUSVString;
     55   
     56    void setTypeConversionsDictionary(TypeConversionsDictionary d);
     57    readonly attribute long typeConversionsDictionaryLongValue;
     58    readonly attribute DOMString typeConversionsDictionaryStringValue;
     59    readonly attribute sequence<DOMString> typeConversionsDictionarySequenceValue;
     60    readonly attribute UnionType typeConversionsDictionaryUnionType;
    5361};
     62
     63dictionary TypeConversionsOtherDictionary {
     64    long longValue = 0;
     65    DOMString stringValue = "";
     66};
     67
     68dictionary TypeConversionsDictionary {
     69    long longValue = 0;
     70    DOMString stringValue = "";
     71    sequence<DOMString> sequenceValue = [];
     72    (Node or sequence<DOMString> or TypeConversionsOtherDictionary) unionValue = null;
     73};
Note: See TracChangeset for help on using the changeset viewer.