Bug 1063889. Fix the handling of sequences of wrapper types in unions. r=khuey
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 08 Sep 2014 11:28:57 -0400
changeset 204168 f0fbb5c6c672985ae41b300f2cc1de590df51030
parent 204167 d0429319c5643df46ec32618a492c4c8bfc62a7c
child 204169 6b8da5940f74dae0c315a014b572e7c4e78ddb35
child 204190 56e2793c8ac7af0fcf0791efbacbf04461cc0e8b
push id27450
push userryanvm@gmail.com
push dateMon, 08 Sep 2014 23:30:01 +0000
treeherdermozilla-central@6b8da5940f74 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1063889
milestone35.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 1063889. Fix the handling of sequences of wrapper types in unions. r=khuey
dom/bindings/Codegen.py
dom/bindings/parser/WebIDL.py
dom/bindings/parser/tests/test_nullable_equivalency.py
dom/bindings/parser/tests/test_typedef.py
dom/bindings/test/TestBindingHeader.h
dom/bindings/test/TestCodeGen.webidl
dom/bindings/test/TestExampleGen.webidl
dom/bindings/test/TestJSImplGen.webidl
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1211,31 +1211,36 @@ def UnionTypes(descriptors, dictionaries
             # FIXME: Unions are broken in workers.  See bug 809899.
             unionStructs[name] = CGUnionStruct(t, providers[0])
             owningUnionStructs[name] = CGUnionStruct(t, providers[0],
                                                      ownsMembers=True)
 
             def addHeadersForType(f):
                 if f.nullable():
                     headers.add("mozilla/dom/Nullable.h")
+                isSequence = f.isSequence()
                 f = f.unroll()
                 if f.isInterface():
                     if f.isSpiderMonkeyInterface():
                         headers.add("jsfriendapi.h")
                         headers.add("mozilla/dom/TypedArray.h")
                     else:
                         for p in providers:
                             try:
                                 typeDesc = p.getDescriptor(f.inner.identifier.name)
                             except NoSuchDescriptorError:
                                 continue
-                            if typeDesc.interface.isCallback():
+                            if typeDesc.interface.isCallback() or isSequence:
                                 # Callback interfaces always use strong refs, so
                                 # we need to include the right header to be able
                                 # to Release() in our inlined code.
+                                #
+                                # Similarly, sequences always contain strong
+                                # refs, so we'll need the header to handler
+                                # those.
                                 headers.add(typeDesc.headerFile)
                             else:
                                 declarations.add((typeDesc.nativeType, False))
                                 implheaders.add(typeDesc.headerFile)
                 elif f.isDictionary():
                     # For a dictionary, we need to see its declaration in
                     # UnionTypes.h so we have its sizeof and know how big to
                     # make our union.
@@ -4646,17 +4651,17 @@ def getJSToNativeConversionInfo(type, de
             holderType = CGGeneric(holderType)
         return JSToNativeConversionInfo(templateBody,
                                         declType=declType,
                                         holderType=holderType,
                                         dealWithOptional=isOptional)
 
     if type.isSpiderMonkeyInterface():
         assert not isEnforceRange and not isClamp
-        name = type.name
+        name = type.unroll().name # unroll() because it may be nullable
         arrayType = CGGeneric(name)
         declType = arrayType
         if type.nullable():
             declType = CGTemplatedType("Nullable", declType)
             objRef = "${declName}.SetValue()"
         else:
             objRef = "${declName}"
 
@@ -6197,18 +6202,16 @@ class CGCallGenerator(CGThing):
         return self.cgRoot.define()
 
 
 def getUnionMemberName(type):
     if type.isGeckoInterface():
         return type.inner.identifier.name
     if type.isEnum():
         return type.inner.identifier.name
-    if type.isArray() or type.isSequence() or type.isMozMap():
-        return str(type)
     return type.name
 
 
 class MethodNotNewObjectError(Exception):
     def __init__(self, typename):
         self.typename = typename
 
 # A counter for making sure that when we're wrapping up things in
@@ -12443,17 +12446,18 @@ class CGNativeMember(ClassMethod):
             return ((typeDecl %
                      self.descriptorProvider.getDescriptor(iface.identifier.name).prettyNativeType),
                     False, False)
 
         if type.isSpiderMonkeyInterface():
             if not self.typedArraysAreStructs:
                 return "JS::Handle<JSObject*>", False, False
 
-            return type.name, True, True
+            # Unroll for the name, in case we're nullable.
+            return type.unroll().name, True, True
 
         if type.isDOMString() or type.isScalarValueString():
             if isMember:
                 declType = "nsString"
             else:
                 declType = "nsAString"
             return declType, True, False
 
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1759,17 +1759,20 @@ class IDLUnresolvedType(IDLType):
         raise TypeError("Can't tell whether an unresolved type is or is not "
                         "distinguishable from other things")
 
 class IDLNullableType(IDLType):
     def __init__(self, location, innerType):
         assert not innerType.isVoid()
         assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any]
 
-        IDLType.__init__(self, location, innerType.name)
+        name = innerType.name
+        if innerType.isComplete():
+            name += "OrNull"
+        IDLType.__init__(self, location, name)
         self.inner = innerType
         self.builtin = False
 
     def __eq__(self, other):
         return isinstance(other, IDLNullableType) and self.inner == other.inner
 
     def __str__(self):
         return self.inner.__str__() + "OrNull"
@@ -1872,17 +1875,17 @@ class IDLNullableType(IDLType):
                               "a nullable type",
                               [self.location, self.inner.location])
         if self.inner.isUnion():
             if self.inner.hasNullableType:
                 raise WebIDLError("The inner type of a nullable type must not "
                                   "be a union type that itself has a nullable "
                                   "type as a member type", [self.location])
 
-        self.name = self.inner.name
+        self.name = self.inner.name + "OrNull"
         return self
 
     def unroll(self):
         return self.inner.unroll()
 
     def isDistinguishableFrom(self, other):
         if (other.nullable() or (other.isUnion() and other.hasNullableType) or
             other.isDictionary()):
@@ -1895,16 +1898,20 @@ class IDLNullableType(IDLType):
 
 class IDLSequenceType(IDLType):
     def __init__(self, location, parameterType):
         assert not parameterType.isVoid()
 
         IDLType.__init__(self, location, parameterType.name)
         self.inner = parameterType
         self.builtin = False
+        # Need to set self.name up front if our inner type is already complete,
+        # since in that case our .complete() won't be called.
+        if self.inner.isComplete():
+            self.name = self.inner.name + "Sequence"
 
     def __eq__(self, other):
         return isinstance(other, IDLSequenceType) and self.inner == other.inner
 
     def __str__(self):
         return self.inner.__str__() + "Sequence"
 
     def nullable(self):
@@ -1956,17 +1963,17 @@ class IDLSequenceType(IDLType):
         assert isinstance(parentScope, IDLScope)
         self.inner.resolveType(parentScope)
 
     def isComplete(self):
         return self.inner.isComplete()
 
     def complete(self, scope):
         self.inner = self.inner.complete(scope)
-        self.name = self.inner.name
+        self.name = self.inner.name + "Sequence"
         return self
 
     def unroll(self):
         return self.inner.unroll()
 
     def isDistinguishableFrom(self, other):
         if other.isUnion():
             # Just forward to the union; it'll deal
@@ -1982,16 +1989,20 @@ class IDLMozMapType(IDLType):
     # And maybe to IDLNullableType.  Should we have a superclass for
     # "type containing this other type"?  Bug 1015318.
     def __init__(self, location, parameterType):
         assert not parameterType.isVoid()
 
         IDLType.__init__(self, location, parameterType.name)
         self.inner = parameterType
         self.builtin = False
+        # Need to set self.name up front if our inner type is already complete,
+        # since in that case our .complete() won't be called.
+        if self.inner.isComplete():
+            self.name = self.inner.name + "MozMap"
 
     def __eq__(self, other):
         return isinstance(other, IDLMozMapType) and self.inner == other.inner
 
     def __str__(self):
         return self.inner.__str__() + "MozMap"
 
     def isMozMap(self):
@@ -2007,17 +2018,17 @@ class IDLMozMapType(IDLType):
         assert isinstance(parentScope, IDLScope)
         self.inner.resolveType(parentScope)
 
     def isComplete(self):
         return self.inner.isComplete()
 
     def complete(self, scope):
         self.inner = self.inner.complete(scope)
-        self.name = self.inner.name
+        self.name = self.inner.name + "MozMap"
         return self
 
     def unroll(self):
         # We do not unroll our inner.  Just stop at ourselves.  That
         # lets us add headers for both ourselves and our inner as
         # needed.
         return self
 
@@ -2072,19 +2083,16 @@ class IDLUnionType(IDLType):
     def complete(self, scope):
         def typeName(type):
             if isinstance(type, IDLNullableType):
                 return typeName(type.inner) + "OrNull"
             if isinstance(type, IDLWrapperType):
                 return typeName(type._identifier.object())
             if isinstance(type, IDLObjectWithIdentifier):
                 return typeName(type.identifier)
-            if (isinstance(type, IDLType) and
-                (type.isArray() or type.isSequence() or type.isMozMap)):
-                return str(type)
             return type.name
 
         for (i, type) in enumerate(self.memberTypes):
             if not type.isComplete():
                 self.memberTypes[i] = type.complete(scope)
 
         self.name = "Or".join(typeName(type) for type in self.memberTypes)
         self.flatMemberTypes = list(self.memberTypes)
--- a/dom/bindings/parser/tests/test_nullable_equivalency.py
+++ b/dom/bindings/parser/tests/test_nullable_equivalency.py
@@ -85,17 +85,17 @@ def checkEquivalent(iface, harness):
     #  - names beginning with '_',
     #  - functions which throw when called with no args, and
     #  - class-level non-callables ("static variables").
     #
     # Yes, this is an ugly, fragile hack.  But it finds bugs...
     for attr in dir(type1):
         if attr.startswith('_') or \
            attr in ['nullable', 'builtin', 'filename', 'location',
-                    'inner', 'QName', 'getDeps'] or \
+                    'inner', 'QName', 'getDeps', 'name'] or \
            (hasattr(type(type1), attr) and not callable(getattr(type1, attr))):
             continue
 
         a1 = getattr(type1, attr)
 
         if callable(a1):
             try:
                 v1 = a1()
--- a/dom/bindings/parser/tests/test_typedef.py
+++ b/dom/bindings/parser/tests/test_typedef.py
@@ -7,17 +7,17 @@ def WebIDLTest(parser, harness):
         const mynullablelong Y = 7;
         const mynullablelong Z = null;
         void foo(mylong arg);
       };
     """)
 
     results = parser.finish()
 
-    harness.check(results[2].members[1].type.name, "Long",
+    harness.check(results[2].members[1].type.name, "LongOrNull",
                   "Should expand typedefs")
 
     parser = parser.reset()
     threw = False
     try:
         parser.parse("""
           typedef long? mynullablelong;
           interface Foo {
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -598,16 +598,20 @@ public:
   void PassUnion15(const LongSequenceOrLong&);
   void PassUnion16(const Optional<LongSequenceOrLong>&);
   void PassUnion17(const LongSequenceOrNullOrLong&);
   void PassUnion18(JSContext*, const ObjectSequenceOrLong&);
   void PassUnion19(JSContext*, const Optional<ObjectSequenceOrLong>&);
   void PassUnion20(JSContext*, const ObjectSequenceOrLong&);
   void PassUnion21(const LongMozMapOrLong&);
   void PassUnion22(JSContext*, const ObjectMozMapOrLong&);
+  void PassUnion23(const ImageDataSequenceOrLong&);
+  void PassUnion24(const ImageDataOrNullSequenceOrLong&);
+  void PassUnion25(const ImageDataSequenceSequenceOrLong&);
+  void PassUnion26(const ImageDataOrNullSequenceSequenceOrLong&);
   void PassUnionWithCallback(const EventHandlerNonNullOrNullOrLong& arg);
   void PassUnionWithByteString(const ByteStringOrLong&);
   void PassUnionWithMozMap(const StringMozMapOrString&);
   void PassUnionWithMozMapAndSequence(const StringMozMapOrStringSequence&);
   void PassUnionWithSequenceAndMozMap(const StringSequenceOrStringMozMap&);
   void PassUnionWithSVS(const ScalarValueStringOrLong&);
 #endif
   void PassNullableUnion(JSContext*, const Nullable<ObjectOrLong>&);
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -562,16 +562,20 @@ interface TestInterface {
   void passUnion15((sequence<long> or long) arg);
   void passUnion16(optional (sequence<long> or long) arg);
   void passUnion17(optional (sequence<long>? or long) arg = 5);
   void passUnion18((sequence<object> or long) arg);
   void passUnion19(optional (sequence<object> or long) arg);
   void passUnion20(optional (sequence<object> or long) arg = []);
   void passUnion21((MozMap<long> or long) arg);
   void passUnion22((MozMap<object> or long) arg);
+  void passUnion23((sequence<ImageData> or long) arg);
+  void passUnion24((sequence<ImageData?> or long) arg);
+  void passUnion25((sequence<sequence<ImageData>> or long) arg);
+  void passUnion26((sequence<sequence<ImageData?>> or long) arg);
   void passUnionWithCallback((EventHandler or long) arg);
   void passUnionWithByteString((ByteString or long) arg);
   void passUnionWithMozMap((MozMap<DOMString> or DOMString) arg);
   void passUnionWithMozMapAndSequence((MozMap<DOMString> or sequence<DOMString>) arg);
   void passUnionWithSequenceAndMozMap((sequence<DOMString> or MozMap<DOMString>) arg);
   void passUnionWithSVS((ScalarValueString or long) arg);
 #endif
   void passUnionWithNullable((object? or long) arg);
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -426,16 +426,20 @@ interface TestExampleInterface {
   void passUnion15((sequence<long> or long) arg);
   void passUnion16(optional (sequence<long> or long) arg);
   void passUnion17(optional (sequence<long>? or long) arg = 5);
   void passUnion18((sequence<object> or long) arg);
   void passUnion19(optional (sequence<object> or long) arg);
   void passUnion20(optional (sequence<object> or long) arg = []);
   void passUnion21((MozMap<long> or long) arg);
   void passUnion22((MozMap<object> or long) arg);
+  void passUnion23((sequence<ImageData> or long) arg);
+  void passUnion24((sequence<ImageData?> or long) arg);
+  void passUnion25((sequence<sequence<ImageData>> or long) arg);
+  void passUnion26((sequence<sequence<ImageData?>> or long) arg);
   void passUnionWithCallback((EventHandler or long) arg);
   void passUnionWithByteString((ByteString or long) arg);
   void passUnionWithMozMap((MozMap<DOMString> or DOMString) arg);
   void passUnionWithMozMapAndSequence((MozMap<DOMString> or sequence<DOMString>) arg);
   void passUnionWithSequenceAndMozMap((sequence<DOMString> or MozMap<DOMString>) arg);
   void passUnionWithSVS((ScalarValueString or long) arg);
 #endif
   void passUnionWithNullable((object? or long) arg);
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -446,16 +446,20 @@ interface TestJSImplInterface {
   void passUnion15((sequence<long> or long) arg);
   void passUnion16(optional (sequence<long> or long) arg);
   void passUnion17(optional (sequence<long>? or long) arg = 5);
   void passUnion18((sequence<object> or long) arg);
   void passUnion19(optional (sequence<object> or long) arg);
   void passUnion20(optional (sequence<object> or long) arg = []);
   void passUnion21((MozMap<long> or long) arg);
   void passUnion22((MozMap<object> or long) arg);
+  void passUnion23((sequence<ImageData> or long) arg);
+  void passUnion24((sequence<ImageData?> or long) arg);
+  void passUnion25((sequence<sequence<ImageData>> or long) arg);
+  void passUnion26((sequence<sequence<ImageData?>> or long) arg);
   void passUnionWithCallback((EventHandler or long) arg);
   void passUnionWithByteString((ByteString or long) arg);
   void passUnionWithMozMap((MozMap<DOMString> or DOMString) arg);
   void passUnionWithMozMapAndSequence((MozMap<DOMString> or sequence<DOMString>) arg);
   void passUnionWithSequenceAndMozMap((sequence<DOMString> or MozMap<DOMString>) arg);
   void passUnionWithSVS((ScalarValueString or long) arg);
 #endif
   void passUnionWithNullable((object? or long) arg);