Bug 819845. Update WebIDL bindings to spec change: sequences/arrays are no longer distinguishable from dictionaries, and conversion to a sequence works on arbitrary objects. r=khuey
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 02 Jan 2013 22:03:25 -0500
changeset 117378 ad6784f8e19b15150d7f154117ed54f20d931092
parent 117377 649dfcc03f382d682de5375a1630a15b9566237c
child 117379 ece40f3875ff435ba05c11f648852dc7fd2756fd
push id20489
push userbzbarsky@mozilla.com
push dateThu, 03 Jan 2013 03:18:02 +0000
treeherdermozilla-inbound@5fae52f44675 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs819845
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 819845. Update WebIDL bindings to spec change: sequences/arrays are no longer distinguishable from dictionaries, and conversion to a sequence works on arbitrary objects. r=khuey
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/parser/WebIDL.py
dom/bindings/parser/tests/test_distinguishability.py
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -205,19 +205,18 @@ IsArrayLike(JSContext* cx, JSObject* obj
     if (!obj) {
       // Let's say it's not
       return false;
     }
 
     ac.construct(cx, obj);
   }
 
-  // XXXbz need to detect platform objects (including listbinding
-  // ones) with indexGetters here!
-  return JS_IsArrayObject(cx, obj) || JS_IsTypedArrayObject(obj);
+  // Everything except dates and regexps is arraylike
+  return !JS_ObjectIsDate(cx, obj) && !JS_ObjectIsRegExp(cx, obj);
 }
 
 inline bool
 IsPlatformObject(JSContext* cx, JSObject* obj)
 {
   // XXXbz Should be treating list-binding objects as platform objects
   // too?  The one consumer so far wants non-array-like platform
   // objects, so listbindings that have an indexGetter should test
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2308,19 +2308,16 @@ for (uint32_t i = 0; i < length; ++i) {
             interfaceObject = None
 
         arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes)
         if len(arrayObjectMemberTypes) > 0:
             assert len(arrayObjectMemberTypes) == 1
             memberType = arrayObjectMemberTypes[0]
             name = memberType.name
             arrayObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${obj}, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
-            # XXX Now we're supposed to check for an array or a platform object
-            # that supports indexed properties... skip that last for now. It's a
-            # bit of a pain.
             arrayObject = CGWrapper(CGIndenter(arrayObject),
                                     pre="if (IsArrayLike(cx, &argObj)) {\n",
                                     post="}")
             names.append(name)
         else:
             arrayObject = None
 
         dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1282,18 +1282,17 @@ class IDLSequenceType(IDLType):
     def unroll(self):
         return self.inner.unroll()
 
     def isDistinguishableFrom(self, other):
         if other.isUnion():
             # Just forward to the union; it'll deal
             return other.isDistinguishableFrom(self)
         return (other.isPrimitive() or other.isString() or other.isEnum() or
-                other.isDictionary() or other.isDate() or
-                other.isNonCallbackInterface())
+                other.isDate() or other.isNonCallbackInterface())
 
 class IDLUnionType(IDLType):
     def __init__(self, location, memberTypes):
         IDLType.__init__(self, location, "")
         self.memberTypes = memberTypes
         self.hasNullableType = False
         self.flatMemberTypes = None
         self.builtin = False
@@ -1447,18 +1446,17 @@ class IDLArrayType(IDLType):
     def unroll(self):
         return self.inner.unroll()
 
     def isDistinguishableFrom(self, other):
         if other.isUnion():
             # Just forward to the union; it'll deal
             return other.isDistinguishableFrom(self)
         return (other.isPrimitive() or other.isString() or other.isEnum() or
-                other.isDictionary() or other.isDate() or
-                other.isNonCallbackInterface())
+                other.isDate() or other.isNonCallbackInterface())
 
 class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
     def __init__(self, location, innerType, name):
         IDLType.__init__(self, location, innerType.name)
 
         identifier = IDLUnresolvedIdentifier(location, name)
 
         IDLObjectWithIdentifier.__init__(self, location, None, identifier)
@@ -1613,26 +1611,24 @@ class IDLWrapperType(IDLType):
             # Just forward to the union; it'll deal
             return other.isDistinguishableFrom(self)
         assert self.isInterface() or self.isEnum() or self.isDictionary()
         if self.isEnum():
             return (other.isInterface() or other.isObject() or
                     other.isCallback() or other.isDictionary() or
                     other.isSequence() or other.isArray() or
                     other.isDate())
+        if self.isDictionary() and other.nullable():
+            return False
         if other.isPrimitive() or other.isString() or other.isEnum() or other.isDate():
             return True
         if self.isDictionary():
-            return (not other.nullable() and
-                    (other.isNonCallbackInterface() or other.isSequence() or
-                     other.isArray()))
+            return other.isNonCallbackInterface()
 
         assert self.isInterface()
-        # XXXbz need to check that the interfaces can't be implemented
-        # by the same object
         if other.isInterface():
             if other.isSpiderMonkeyInterface():
                 # Just let |other| handle things
                 return other.isDistinguishableFrom(self)
             assert self.isGeckoInterface() and other.isGeckoInterface()
             if self.inner.isExternal() or other.unroll().inner.isExternal():
                 return self != other
             return (len(self.inner.interfacesBasedOnSelf &
--- a/dom/bindings/parser/tests/test_distinguishability.py
+++ b/dom/bindings/parser/tests/test_distinguishability.py
@@ -143,8 +143,114 @@ def WebIDLTest(parser, harness):
             void method(DOMString arg1, DOMString arg2, DOMString arg3);
           };
         """)
         results = parser.finish()
     except:
         threw = True
 
     harness.ok(threw, "Should throw when there is no distinguishing index")
+
+    # Now let's test our whole distinguishability table
+    argTypes = [ "long", "short", "long?", "short?", "DOMString", "Enum",
+                 "Enum2", "Interface", "Interface?",
+                 "AncestorInterface", "UnrelatedInterface",
+                 "ImplementedInterface", "CallbackInterface",
+                 "CallbackInterface?", "CallbackInterface2",
+                 "object", "Callback", "Callback2", "optional Dict",
+                 "optional Dict2", "sequence<long>", "sequence<short>",
+                 "long[]", "short[]" ]
+    # When we can parse Date and RegExp, we need to add them here.
+
+    # Try to categorize things a bit to keep list lengths down
+    def allBut(list1, list2):
+        return [a for a in list1 if a not in list2]
+    primitives = [ "long", "short", "long?", "short?", "DOMString",
+                   "Enum", "Enum2" ]
+    nonPrimitives = allBut(argTypes, primitives)
+    interfaces = [ "Interface", "Interface?", "AncestorInterface",
+                   "UnrelatedInterface", "ImplementedInterface" ]
+    nullables = ["long?", "short?", "Interface?", "CallbackInterface?",
+                 "optional Dict", "optional Dict2"]
+    nonUserObjects = primitives + interfaces
+    otherObjects = allBut(argTypes, nonUserObjects + ["object"])
+    notRelatedInterfaces = primitives + ["UnrelatedInterface"] + otherObjects
+
+    # Build a representation of the distinguishability table as a dict
+    # of dicts, holding True values where needed, holes elsewhere.
+    data = dict();
+    for type in argTypes:
+        data[type] = dict()
+    def setDistinguishable(type, types):
+        for other in types:
+            data[type][other] = True
+
+    setDistinguishable("long", nonPrimitives)
+    setDistinguishable("short", nonPrimitives)
+    setDistinguishable("long?", allBut(nonPrimitives, nullables))
+    setDistinguishable("short?", allBut(nonPrimitives, nullables))
+    setDistinguishable("DOMString", nonPrimitives)
+    setDistinguishable("Enum", nonPrimitives)
+    setDistinguishable("Enum2", nonPrimitives)
+    setDistinguishable("Interface", notRelatedInterfaces)
+    setDistinguishable("Interface?", allBut(notRelatedInterfaces, nullables))
+    setDistinguishable("AncestorInterface", notRelatedInterfaces)
+    setDistinguishable("UnrelatedInterface",
+                       allBut(argTypes, ["object", "UnrelatedInterface"]))
+    setDistinguishable("ImplementedInterface", notRelatedInterfaces)
+    setDistinguishable("CallbackInterface", nonUserObjects)
+    setDistinguishable("CallbackInterface?", allBut(nonUserObjects, nullables))
+    setDistinguishable("CallbackInterface2", nonUserObjects)
+    setDistinguishable("object", primitives)
+    setDistinguishable("Callback", nonUserObjects)
+    setDistinguishable("Callback2", nonUserObjects)
+    setDistinguishable("optional Dict", allBut(nonUserObjects, nullables))
+    setDistinguishable("optional Dict2", allBut(nonUserObjects, nullables))
+    setDistinguishable("sequence<long>", nonUserObjects)
+    setDistinguishable("sequence<short>", nonUserObjects)
+    setDistinguishable("long[]", nonUserObjects)
+    setDistinguishable("short[]", nonUserObjects)
+
+    def areDistinguishable(type1, type2):
+        return data[type1].get(type2, False)
+
+    def checkDistinguishability(parser, type1, type2):
+        idlTemplate = """
+          enum Enum { "a", "b" };
+          enum Enum2 { "c", "d" };
+          interface Interface : AncestorInterface {};
+          interface AncestorInterface {};
+          interface UnrelatedInterface {};
+          interface ImplementedInterface {};
+          Interface implements ImplementedInterface;
+          callback interface CallbackInterface {};
+          callback interface CallbackInterface2 {};
+          callback Callback = any();
+          callback Callback2 = long(short arg);
+          dictionary Dict {};
+          dictionary Dict2 {};
+          interface TestInterface {%s
+          };
+        """
+        methodTemplate = """
+            void myMethod(%s arg);"""
+        methods = (methodTemplate % type1) + (methodTemplate % type2)
+        idl = idlTemplate % methods
+        parser = parser.reset()
+        threw = False
+        try:
+            parser.parse(idl)
+            results = parser.finish()
+        except:
+            threw = True
+
+        if areDistinguishable(type1, type2):
+            harness.ok(not threw,
+                       "Should not throw for '%s' and '%s' because they are distinguishable" % (type1, type2))
+        else:
+            harness.ok(threw,
+                       "Should throw for '%s' and '%s' because they are not distinguishable" % (type1, type2))
+
+    # Enumerate over everything in both orders, since order matters in
+    # terms of our implementation of distinguishability checks
+    for type1 in argTypes:
+        for type2 in argTypes:
+            checkDistinguishability(parser, type1, type2)