Backout 9deb8edb5070 (bug 773519), ea5a243a60f1 & 0cad1e553bea (bug 768537) for compilation failures
authorEd Morley <emorley@mozilla.com>
Tue, 17 Jul 2012 17:48:11 +0100
changeset 105029 8212be806c67ef0d23eddf7e44076ddd33e3721f
parent 105028 e5b62d2de1230fec4a3527d9596bfc905ecdeac6
child 105030 e29a8552778256b22e08f98b7c241ed0dc90d47e
push idunknown
push userunknown
push dateunknown
bugs773519, 768537
milestone17.0a1
backs out9deb8edb5070643091049171c2188aba43b31afc
Backout 9deb8edb5070 (bug 773519), ea5a243a60f1 & 0cad1e553bea (bug 768537) for compilation failures
content/base/src/nsXMLHttpRequest.h
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/parser/WebIDL.py
dom/bindings/parser/tests/test_dictionary.py
dom/bindings/parser/tests/test_distinguishability.py
dom/bindings/test/TestBindingHeader.h
dom/bindings/test/TestCodeGen.webidl
dom/webidl/XMLHttpRequest.webidl
dom/workers/XMLHttpRequest.cpp
dom/workers/XMLHttpRequest.h
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -176,29 +176,32 @@ public:
   {
     return GetOwner();
   }
 
   // The WebIDL constructor.
   static already_AddRefed<nsXMLHttpRequest>
   Constructor(JSContext* aCx,
               nsISupports* aGlobal,
-              const mozilla::dom::MozXMLHttpRequestParameters& aParams,
+              const mozilla::dom::Nullable<mozilla::dom::MozXMLHttpRequestParameters>& aParams,
               ErrorResult& aRv)
   {
     nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal);
     nsCOMPtr<nsIScriptObjectPrincipal> principal = do_QueryInterface(aGlobal);
     if (!window || ! principal) {
       aRv.Throw(NS_ERROR_FAILURE);
       return NULL;
     }
 
     nsRefPtr<nsXMLHttpRequest> req = new nsXMLHttpRequest();
     req->Construct(principal->GetPrincipal(), window);
-    req->InitParameters(aParams.mozAnon, aParams.mozSystem);
+    if (!aParams.IsNull()) {
+      const mozilla::dom::MozXMLHttpRequestParameters& params = aParams.Value();
+      req->InitParameters(params.mozAnon, params.mozSystem);
+    }
     return req.forget();
   }
 
   void Construct(nsIPrincipal* aPrincipal,
                  nsPIDOMWindow* aOwnerWindow,
                  nsIURI* aBaseURI = NULL)
   {
     MOZ_ASSERT(aPrincipal);
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -677,25 +677,16 @@ public:
   void operator=(T* t) {
     ptr = t;
     MOZ_ASSERT(ptr);
 #ifdef DEBUG
     inited = true;
 #endif
   }
 
-  template<typename U>
-  void operator=(U* t) {
-    ptr = t->ToAStringPtr();
-    MOZ_ASSERT(ptr);
-#ifdef DEBUG
-    inited = true;
-#endif
-  }
-
   T** Slot() {
 #ifdef DEBUG
     inited = true;
 #endif
     return &ptr;
   }
 
 protected:
@@ -740,93 +731,27 @@ protected:
   }
 
   nsRefPtr<T> ptr;
 #ifdef DEBUG
   bool inited;
 #endif
 };
 
-// A struct that has the same layout as an nsDependentString but much
-// faster constructor and destructor behavior
-struct FakeDependentString {
-  FakeDependentString() :
-    mFlags(nsDependentString::F_TERMINATED)
-  {
-  }
-
-  void SetData(const nsDependentString::char_type* aData,
-               nsDependentString::size_type aLength) {
-    MOZ_ASSERT(mFlags == nsDependentString::F_TERMINATED);
-    mData = aData;
-    mLength = aLength;
-  }
-
-  void Truncate() {
-    mData = nsnull;
-    mLength = 0;
-  }
-
-  void SetNull() {
-    Truncate();
-    mFlags |= nsDependentString::F_VOIDED;
-  }
-
-  const nsAString* ToAStringPtr() const {
-    return reinterpret_cast<const nsDependentString*>(this);
-  }
-
-  nsAString* ToAStringPtr() {
-    return reinterpret_cast<nsDependentString*>(this);
-  }
-
-  operator const nsAString& () const {
-    return *reinterpret_cast<const nsDependentString*>(this);
-  }
-
-private:
-  const nsDependentString::char_type* mData;
-  nsDependentString::size_type mLength;
-  PRUint32 mFlags;
-
-  // A class to use for our static asserts to ensure our object layout
-  // matches that of nsDependentString.
-  class DepedentStringAsserter : public nsDependentString {
-  public:
-    static const size_t dataOffset = offsetof(nsDependentString, mData);
-    static const size_t lengthOffset = offsetof(nsDependentString, mLength);
-    static const size_t flagsOffset = offsetof(nsDependentString, mFlags);
-  };
-
-  static void StaticAsserts() {
-    MOZ_STATIC_ASSERT(sizeof(FakeDependentString) == sizeof(nsDependentString),
-                      "Must have right object size");
-    MOZ_STATIC_ASSERT(offsetof(FakeDependentString, mData) ==
-                        DepedentStringAsserter::dataOffset,
-                      "Offset of mData should match");
-    MOZ_STATIC_ASSERT(offsetof(FakeDependentString, mLength) ==
-                        DepedentStringAsserter::lengthOffset,
-                      "Offset of mLength should match");
-    MOZ_STATIC_ASSERT(offsetof(FakeDependentString, mFlags) ==
-                        DepedentStringAsserter::flagsOffset,
-                      "Offset of mFlags should match");
-  }
-};
-
 enum StringificationBehavior {
   eStringify,
   eEmpty,
   eNull
 };
 
 static inline bool
 ConvertJSValueToString(JSContext* cx, const JS::Value& v, JS::Value* pval,
                        StringificationBehavior nullBehavior,
                        StringificationBehavior undefinedBehavior,
-                       FakeDependentString& result)
+                       nsDependentString& result)
 {
   JSString *s;
   if (v.isString()) {
     s = v.toString();
   } else {
     StringificationBehavior behavior;
     if (v.isNull()) {
       behavior = nullBehavior;
@@ -837,38 +762,34 @@ ConvertJSValueToString(JSContext* cx, co
     }
 
     // If pval is null, that means the argument was optional and
     // not passed; turn those into void strings if they're
     // supposed to be stringified.
     if (behavior != eStringify || !pval) {
       // Here behavior == eStringify implies !pval, so both eNull and
       // eStringify should end up with void strings.
-      if (behavior == eEmpty) {
-        result.Truncate();
-      } else {
-        result.SetNull();
-      }
+      result.SetIsVoid(behavior != eEmpty);
       return true;
     }
 
     s = JS_ValueToString(cx, v);
     if (!s) {
       return false;
     }
     pval->setString(s);  // Root the new string.
   }
 
   size_t len;
   const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
   if (!chars) {
     return false;
   }
 
-  result.SetData(chars, len);
+  result.Rebind(chars, len);
   return true;
 }
 
 // Class for representing optional arguments.
 template<typename T>
 class Optional {
 public:
   Optional() {}
@@ -913,22 +834,16 @@ public:
   }
 
   void operator=(const nsAString* str) {
     MOZ_ASSERT(str);
     mStr = str;
     mPassed = true;
   }
 
-  void operator=(const FakeDependentString* str) {
-    MOZ_ASSERT(str);
-    mStr = str->ToAStringPtr();
-    mPassed = true;
-  }
-
   const nsAString& Value() const {
     MOZ_ASSERT(WasPassed());
     return *mStr;
   }
 
 private:
   // Forbid copy-construction and assignment
   Optional(const Optional& other) MOZ_DELETE;
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1972,17 +1972,17 @@ for (uint32_t i = 0; i < length; ++i) {
             undefinedBehavior = "eStringify"
 
         if isMember:
             # We have to make a copy, because our jsval may well not
             # live as long as our string needs to.
             declType = CGGeneric("nsString")
             return (
                 "{\n"
-                "  FakeDependentString str;\n"
+                "  nsDependentString str;\n"
                 "  if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, str)) {\n"
                 "    return false;\n"
                 "  }\n"
                 "  ${declName} = str;\n"
                 "}\n" %
                 (nullBehavior, undefinedBehavior),
             declType, None,
             isOptional)
@@ -1992,17 +1992,17 @@ for (uint32_t i = 0; i < length; ++i) {
         else:
             declType = "NonNull<nsAString>"
         return (
             "if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, ${holderName})) {\n"
             "  return false;\n"
             "}\n"
             "const_cast<%s&>(${declName}) = &${holderName};" %
             (nullBehavior, undefinedBehavior, declType),
-            CGGeneric("const " + declType), CGGeneric("FakeDependentString"),
+            CGGeneric("const " + declType), CGGeneric("nsDependentString"),
             # No need to deal with Optional here; we have handled it already
             False)
 
     if type.isEnum():
         if type.nullable():
             raise TypeError("We don't support nullable enumerated arguments "
                             "yet")
         enum = type.inner.identifier.name
@@ -2053,40 +2053,45 @@ for (uint32_t i = 0; i < length; ++i) {
             declType = CGGeneric("JSObject*")
         else:
             declType = CGGeneric("NonNull<JSObject>")
         return (template, declType, None, isOptional)
 
     if type.isDictionary():
         if failureCode is not None:
             raise TypeError("Can't handle dictionaries when failureCode is not None")
-        # There are no nullable dictionaries
-        assert not type.nullable()
-        # All optional dictionaries always have default values, so we
-        # should be able to assume not isOptional here.
-        assert not isOptional
-
-        typeName = CGDictionary.makeDictionaryName(type.inner,
-                                                   descriptorProvider.workers)
-        actualTypeName = typeName
-        selfRef = "${declName}"
+
+        if type.nullable():
+            typeName = CGDictionary.makeDictionaryName(type.inner.inner,
+                                                       descriptorProvider.workers)
+            actualTypeName = "Nullable<%s>" % typeName
+            selfRef = "const_cast<%s&>(${declName}).SetValue()" % actualTypeName
+        else:
+            typeName = CGDictionary.makeDictionaryName(type.inner,
+                                                       descriptorProvider.workers)
+            actualTypeName = typeName
+            selfRef = "${declName}"
 
         declType = CGGeneric(actualTypeName)
 
-        # If we're a member of something else, the const
+        # If we're optional or a member of something else, the const
         # will come from the Optional or our container.
-        if not isMember:
+        if not isOptional and not isMember:
             declType = CGWrapper(declType, pre="const ")
             selfRef = "const_cast<%s&>(%s)" % (typeName, selfRef)
 
-        template = ("if (!%s.Init(cx, ${val})) {\n"
-                    "  return false;\n"
-                    "}" % selfRef)
-
-        return (template, declType, None, False)
+        template = wrapObjectTemplate("if (!%s.Init(cx, &${val}.toObject())) {\n"
+                                      "  return false;\n"
+                                      "}" % selfRef,
+                                      isDefinitelyObject, type,
+                                      ("const_cast<%s&>(${declName}).SetNull()" %
+                                       actualTypeName),
+                                      descriptorProvider.workers, None)
+
+        return (template, declType, None, isOptional)
 
     if not type.isPrimitive():
         raise TypeError("Need conversion for argument type '%s'" % type)
 
     # XXXbz need to add support for [EnforceRange] and [Clamp]
     typeName = builtinNames[type.tag()]
     if type.nullable():
         return ("if (${val}.isNullOrUndefined()) {\n"
@@ -2823,23 +2828,16 @@ class CGMethodCall(CGThing):
                         CGCase(str(argCount), None, True))
                 else:
                     argCountCases.append(
                         CGCase(str(argCount), getPerSignatureCall(signature)))
                 continue
 
             distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
 
-            # We can't handle unions at the distinguishing index.
-            for (returnType, args) in possibleSignatures:
-                if args[distinguishingIndex].type.isUnion():
-                    raise TypeError("No support for unions as distinguishing "
-                                    "arguments yet: %s",
-                                    args[distinguishingIndex].location)
-
             # Convert all our arguments up to the distinguishing index.
             # Doesn't matter which of the possible signatures we use, since
             # they all have the same types up to that point; just use
             # possibleSignatures[0]
             caseBody = [CGGeneric("JS::Value* argv_start = JS_ARGV(cx, vp);")]
             caseBody.extend([ CGArgumentConverter(possibleSignatures[0][1][i],
                                                   i, "argv_start", "argc",
                                                   descriptor) for i in
@@ -2860,18 +2858,17 @@ class CGMethodCall(CGThing):
                         caseBody.append(CGIndenter(
                                 getPerSignatureCall(sigs[0], distinguishingIndex)))
                         caseBody.append(CGGeneric("}"))
                     return True
                 return False
 
             # First check for null or undefined
             pickFirstSignature("%s.isNullOrUndefined()" % distinguishingArg,
-                               lambda s: (s[1][distinguishingIndex].type.nullable() or
-                                          s[1][distinguishingIndex].type.isDictionary()))
+                               lambda s: s[1][distinguishingIndex].type.nullable())
 
             # Now check for distinguishingArg being an object that implements a
             # non-callback interface.  That includes typed arrays and
             # arraybuffers.
             interfacesSigs = [
                 s for s in possibleSignatures
                 if (s[1][distinguishingIndex].type.isObject() or
                     s[1][distinguishingIndex].type.isNonCallbackInterface()) ]
@@ -3280,18 +3277,16 @@ def getUnionAccessorSignatureType(type, 
     typeName = CGGeneric(builtinNames[type.tag()])
     if type.nullable():
         typeName = CGWrapper(typeName, pre="Nullable< ", post=" >&")
     return typeName
 
 def getUnionTypeTemplateVars(type, descriptorProvider):
     # For dictionaries and sequences we need to pass None as the failureCode
     # for getJSToNativeConversionTemplate.
-    # Also, for dictionaries we would need to handle conversion of
-    # null/undefined to the dictionary correctly.
     if type.isDictionary() or type.isSequence():
         raise TypeError("Can't handle dictionaries or sequences in unions")
 
     if type.isGeckoInterface():
         name = type.inner.identifier.name
     elif type.isEnum():
         name = type.inner.identifier.name
     elif type.isArray() or type.isSequence():
@@ -4106,17 +4101,17 @@ class CGDictionary(CGThing):
             inheritance = ""
         memberDecls = ["  %s %s;" %
                        (self.getMemberType(m), m[0].identifier.name)
                        for m in self.memberInfo]
 
         return (string.Template(
                 "struct ${selfName} ${inheritance}{\n"
                 "  ${selfName}() {}\n"
-                "  bool Init(JSContext* cx, const JS::Value& val);\n"
+                "  bool Init(JSContext* cx, JSObject* obj);\n"
                 "\n" +
                 "\n".join(memberDecls) + "\n"
                 "private:\n"
                 "  // Disallow copy-construction\n"
                 "  ${selfName}(const ${selfName}&) MOZ_DELETE;\n"
                 "  static bool InitIds(JSContext* cx);\n"
                 "  static bool initedIds;\n" +
                 "\n".join("  static jsid " +
@@ -4126,17 +4121,17 @@ class CGDictionary(CGThing):
                                     "inheritance": inheritance }))
 
     def define(self):
         if not self.generatable:
             return ""
         d = self.dictionary
         if d.parent:
             initParent = ("// Per spec, we init the parent's members first\n"
-                          "if (!%s::Init(cx, val)) {\n"
+                          "if (!%s::Init(cx, obj)) {\n"
                           "  return false;\n"
                           "}\n" % self.makeClassName(d.parent))
         else:
             initParent = ""
 
         memberInits = [CGIndenter(self.getMemberConversion(m)).define()
                        for m in self.memberInfo]
         idinit = [CGGeneric('!InternJSString(cx, %s, "%s")' %
@@ -4160,37 +4155,32 @@ class CGDictionary(CGThing):
             "{\n"
             "  MOZ_ASSERT(!initedIds);\n"
             "${idInit}\n"
             "  initedIds = true;\n"
             "  return true;\n"
             "}\n"
             "\n"
             "bool\n"
-            "${selfName}::Init(JSContext* cx, const JS::Value& val)\n"
+            "${selfName}::Init(JSContext* cx, JSObject* obj)\n"
             "{\n"
             "  if (!initedIds && !InitIds(cx)) {\n"
             "    return false;\n"
             "  }\n"
             "${initParent}"
             "  JSBool found;\n"
             "  JS::Value temp;\n"
-            "  bool isNull = val.isNullOrUndefined();\n"
-            "  if (!isNull && !val.isObject()) {\n"
-            "    return Throw<${isMainThread}>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
-            "  }\n"
             "\n"
             "${initMembers}\n"
             "  return true;\n"
             "}").substitute({
                 "selfName": self.makeClassName(d),
                 "initParent": CGIndenter(CGGeneric(initParent)).define(),
                 "initMembers": "\n\n".join(memberInits),
-                "idInit": CGIndenter(idinit).define(),
-                "isMainThread": toStringBool(not self.workers)
+                "idInit": CGIndenter(idinit).define()
                 })
 
     @staticmethod
     def makeDictionaryName(dictionary, workers):
         suffix = "Workers" if workers else ""
         return dictionary.identifier.name + suffix
 
     def makeClassName(self, dictionary):
@@ -4227,38 +4217,36 @@ class CGDictionary(CGThing):
         if dealWithOptional:
             replacements["declName"] = "(" + replacements["declName"] + ".Value())"
 
         conversionReplacements = {
             "propId" : self.makeIdName(member.identifier.name),
             "prop": "(this->%s)" % member.identifier.name,
             "convert": string.Template(templateBody).substitute(replacements)
             }
-        conversion = ("if (isNull) {\n"
-                      "  found = false;\n"
-                      "} else if (!JS_HasPropertyById(cx, &val.toObject(), ${propId}, &found)) {\n"
+        conversion = ("if (!JS_HasPropertyById(cx, obj, ${propId}, &found)) {\n"
                       "  return false;\n"
                       "}\n")
         if member.defaultValue:
             conversion += (
                 "if (found) {\n"
-                "  if (!JS_GetPropertyById(cx, &val.toObject(), ${propId}, &temp)) {\n"
+                "  if (!JS_GetPropertyById(cx, obj, ${propId}, &temp)) {\n"
                 "    return false;\n"
                 "  }\n"
                 "} else {\n"
                 "  temp = ${defaultVal};\n"
                 "}\n"
                 "${convert}")
             conversionReplacements["defaultVal"] = (
                 convertIDLDefaultValueToJSVal(member.defaultValue))
         else:
             conversion += (
                 "if (found) {\n"
                 "  ${prop}.Construct();\n"
-                "  if (!JS_GetPropertyById(cx, &val.toObject(), ${propId}, &temp)) {\n"
+                "  if (!JS_GetPropertyById(cx, obj, ${propId}, &temp)) {\n"
                 "    return false;\n"
                 "  }\n"
                 "${convert}\n"
                 "}")
             conversionReplacements["convert"] = CGIndenter(
                 CGGeneric(conversionReplacements["convert"])).define()
         
         return CGGeneric(
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -702,19 +702,21 @@ class IDLDictionary(IDLObjectWithScope):
                                   [oldParent.location, self.parent.location])
 
             # Make sure the parent resolves all its members before we start
             # looking at them.
             self.parent.finish(scope)
 
         for member in self.members:
             member.resolve(self)
-            if not member.isComplete():
-                member.complete(scope)
-                assert member.type.isComplete()
+            if not member.type.isComplete():
+                type = member.type.complete(scope)
+                assert not isinstance(type, IDLUnresolvedType)
+                assert not isinstance(type.name, IDLUnresolvedIdentifier)
+                member.type = type
 
         # Members of a dictionary are sorted in lexicographic order
         self.members.sort(cmp=cmp, key=lambda x: x.identifier.name)
 
         inheritedMembers = []
         ancestor = self.parent
         while ancestor:
             if ancestor == self:
@@ -1012,42 +1014,28 @@ class IDLNullableType(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)
-        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])
-            # Check for dictionaries in the union
-            for memberType in self.inner.flatMemberTypes:
-                if memberType.isDictionary():
-                    raise WebIDLError("The inner type of a nullable type must "
-                                      "not be a union type containing a "
-                                      "dictionary type",
-                                      [self.location, memberType.location])
-                    
-        if self.inner.isDictionary():
+        if self.inner.isUnion() and self.inner.hasNullableType:
             raise WebIDLError("The inner type of a nullable type must not be a "
-                              "dictionary type", [self.location])
-
+                              "union type that itself has a nullable type as a "
+                              "member type", [self.location])
         self.name = self.inner.name
         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()):
+        if other.nullable() or (other.isUnion() and other.hasNullableType):
             # Can't tell which type null should become
             return False
         return self.inner.isDistinguishableFrom(other)
 
 class IDLSequenceType(IDLType):
     def __init__(self, location, parameterType):
         assert not parameterType.isVoid()
 
@@ -1412,19 +1400,18 @@ class IDLWrapperType(IDLType):
         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 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() or other.isSequence() or
+                    other.isArray())
 
         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)
@@ -1734,19 +1721,17 @@ class IDLValue(IDLObject):
 
 class IDLNullValue(IDLObject):
     def __init__(self, location):
         IDLObject.__init__(self, location)
         self.type = None
         self.value = None
 
     def coerceToType(self, type, location):
-        if (not isinstance(type, IDLNullableType) and
-            not (type.isUnion() and type.hasNullableType) and
-            not type.isDictionary()):
+        if not isinstance(type, IDLNullableType) and not (type.isUnion() and type.hasNullableType):
             raise WebIDLError("Cannot coerce null value to type %s." % type,
                               [location])
 
         nullValue = IDLNullValue(self.location)
         nullValue.type = type
         return nullValue
         
 
@@ -1872,64 +1857,40 @@ class IDLAttribute(IDLInterfaceMember):
 
 class IDLArgument(IDLObjectWithIdentifier):
     def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False):
         IDLObjectWithIdentifier.__init__(self, location, None, identifier)
 
         assert isinstance(type, IDLType)
         self.type = type
 
+        if defaultValue:
+            defaultValue = defaultValue.coerceToType(type, location)
+            assert defaultValue
+
         self.optional = optional
         self.defaultValue = defaultValue
         self.variadic = variadic
         self.dictionaryMember = dictionaryMember
-        self._isComplete = False
 
         assert not variadic or optional
 
     def addExtendedAttributes(self, attrs):
         if self.dictionaryMember:
             for (attr, value) in attrs:
                 if attr == "TreatUndefinedAs":
                     raise WebIDLError("[TreatUndefinedAs] is not allowed for "
                                       "dictionary members", [self.location])
                 elif attr == "TreatNullAs":
                     raise WebIDLError("[TreatNullAs] is not allowed for "
                                       "dictionary members", [self.location])
 
         # But actually, we can't handle this at all, so far.
         assert len(attrs) == 0
 
-    def isComplete(self):
-        return self._isComplete
-
-    def complete(self, scope):
-        if self._isComplete:
-            return
-
-        self._isComplete = True
-
-        if not self.type.isComplete():
-            type = self.type.complete(scope)
-            assert not isinstance(type, IDLUnresolvedType)
-            assert not isinstance(type.name, IDLUnresolvedIdentifier)
-            self.type = type
-
-        if self.type.isDictionary() and self.optional and not self.defaultValue:
-            # Default optional dictionaries to null, for simplicity,
-            # so the codegen doesn't have to special-case this.
-            self.defaultValue = IDLNullValue(self.location)
-
-        # Now do the coercing thing; this needs to happen after the
-        # above creation of a default value.
-        if self.defaultValue:
-            self.defaultValue = self.defaultValue.coerceToType(self.type,
-                                                               self.location)
-            assert self.defaultValue
-
 class IDLCallbackType(IDLType, IDLObjectWithScope):
     def __init__(self, location, parentScope, identifier, returnType, arguments):
         assert isinstance(returnType, IDLType)
 
         IDLType.__init__(self, location, identifier.name)
 
         self._returnType = returnType
         # Clone the list
@@ -2072,16 +2033,44 @@ class IDLMethod(IDLInterfaceMember, IDLS
             assert not arguments[1].optional and not arguments[1].variadic
 
         if self._stringifier:
             assert len(self._overloads) == 1
             overload = self._overloads[0]
             assert len(overload.arguments) == 0
             assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring]
 
+        inOptionalArguments = False
+        variadicArgument = None
+        sawOptionalWithNoDefault = False
+
+        assert len(self._overloads) == 1
+        arguments = self._overloads[0].arguments
+
+        for argument in arguments:
+            # Only the last argument can be variadic
+            if variadicArgument:
+                raise WebIDLError("Variadic argument is not last argument",
+                                  [variadicArgument.location])
+            # Once we see an optional argument, there can't be any non-optional
+            # arguments.
+            if inOptionalArguments and not argument.optional:
+                raise WebIDLError("Non-optional argument after optional arguments",
+                                  [argument.location])
+            # Once we see an argument with no default value, there can
+            # be no more default values.
+            if sawOptionalWithNoDefault and argument.defaultValue:
+                raise WebIDLError("Argument with default value after optional "
+                                  "arguments with no default values",
+                                  [argument.location])
+            inOptionalArguments = argument.optional
+            if argument.variadic:
+                variadicArgument = argument
+            sawOptionalWithNoDefault = argument.optional and not argument.defaultValue
+
     def isStatic(self):
         return self._static
 
     def isGetter(self):
         return self._getter
 
     def isSetter(self):
         return self._setter
@@ -2154,59 +2143,25 @@ class IDLMethod(IDLInterfaceMember, IDLS
         return self
 
     def signatures(self):
         return [(overload.returnType, overload.arguments) for overload in
                 self._overloads]
 
     def finish(self, scope):
         for overload in self._overloads:
-            inOptionalArguments = False
-            variadicArgument = None
-            sawOptionalWithNoDefault = False
-
-            arguments = overload.arguments
-            for (idx, argument) in enumerate(arguments):
-                if argument.isComplete():
+            for argument in overload.arguments:
+                if argument.type.isComplete():
                     continue
 
-                argument.complete(scope)
-                assert argument.type.isComplete()
-
-                if argument.type.isDictionary():
-                    # Dictionaries at the end of the list or followed by
-                    # optional arguments must be optional.
-                    if (not argument.optional and
-                        (idx == len(arguments) - 1 or arguments[idx+1].optional)):
-                        raise WebIDLError("Dictionary argument not followed by "
-                                          "a required argument must be "
-                                          "optional", [argument.location])
-
-                # Only the last argument can be variadic
-                if variadicArgument:
-                    raise WebIDLError("Variadic argument is not last argument",
-                                      [variadicArgument.location])
-                # Once we see an optional argument, there can't be any non-optional
-                # arguments.
-                if inOptionalArguments and not argument.optional:
-                    raise WebIDLError("Non-optional argument after optional "
-                                      "arguments",
-                                      [argument.location])
-                # Once we see an argument with no default value, there can
-                # be no more default values.
-                if sawOptionalWithNoDefault and argument.defaultValue:
-                    raise WebIDLError("Argument with default value after "
-                                      "optional arguments with no default "
-                                      "values",
-                                      [argument.location])
-                inOptionalArguments = argument.optional
-                if argument.variadic:
-                    variadicArgument = argument
-                sawOptionalWithNoDefault = (argument.optional and
-                                            not argument.defaultValue)
+                type = argument.type.complete(scope)
+
+                assert not isinstance(type, IDLUnresolvedType)
+                assert not isinstance(type.name, IDLUnresolvedIdentifier)
+                argument.type = type
 
             returnType = overload.returnType
             if returnType.isComplete():
                 continue
 
             type = returnType.complete(scope)
 
             assert not isinstance(type, IDLUnresolvedType)
--- a/dom/bindings/parser/tests/test_dictionary.py
+++ b/dom/bindings/parser/tests/test_dictionary.py
@@ -116,83 +116,8 @@ def WebIDLTest(parser, harness):
               [TreatUndefinedAs=EmptyString] DOMString foo;
             };
         """)
         results = parser.finish()
     except:
         threw = True
 
     harness.ok(threw, "Should not allow [TreatUndefinedAs] on dictionary members");
-
-    parser = parser.reset()
-    threw = False
-    try:
-        parser.parse("""
-            dictionary A {
-            };
-            interface X {
-              void doFoo(A arg);
-            };
-        """)
-        results = parser.finish()
-    except:
-        threw = True
-
-    harness.ok(threw, "Trailing dictionary arg must be optional")
-
-    parser = parser.reset()
-    threw = False
-    try:
-        parser.parse("""
-            dictionary A {
-            };
-            interface X {
-              void doFoo(A arg1, optional long arg2);
-            };
-        """)
-        results = parser.finish()
-    except:
-        threw = True
-
-    harness.ok(threw, "Dictionary arg followed by optional arg must be optional")
-
-    parser = parser.reset()
-    parser.parse("""
-            dictionary A {
-            };
-            interface X {
-              void doFoo(A arg1, long arg2);
-            };
-        """)
-    results = parser.finish()
-    harness.ok(True, "Dictionary arg followed by required arg can be required")
-
-    parser = parser.reset()
-    threw = False
-    try:
-        parser.parse("""
-            dictionary A {
-            };
-            interface X {
-              void doFoo(optional A? arg1);
-            };
-        """)
-        results = parser.finish()
-    except:
-        threw = True
-
-    harness.ok(threw, "Dictionary arg must not be nullable")
-
-    parser = parser.reset()
-    threw = False
-    try:
-        parser.parse("""
-            dictionary A {
-            };
-            interface X {
-              void doFoo((A or long)? arg1);
-            };
-        """)
-        results = parser.finish()
-    except:
-        threw = True
-
-    harness.ok(threw, "Dictionary arg must not be in a nullable union")
--- a/dom/bindings/parser/tests/test_distinguishability.py
+++ b/dom/bindings/parser/tests/test_distinguishability.py
@@ -4,17 +4,17 @@ def firstArgType(method):
 def WebIDLTest(parser, harness):
     parser.parse("""
       dictionary Dict {
       };
       callback interface Foo {
       };
       interface Bar {
         // Bit of a pain to get things that have dictionary types
-        void passDict(optional Dict arg);
+        void passDict(Dict arg);
         void passFoo(Foo arg);
         void passNullableUnion((object? or DOMString) arg);
         void passNullable(Foo? arg);
       };
     """)
     results = parser.finish()
 
     iface = results[2]
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -341,20 +341,21 @@ public:
   void MethodRenamedTo(ErrorResult&);
   void MethodRenamedTo(int8_t, ErrorResult&);
   int8_t GetAttributeGetterRenamedTo(ErrorResult&);
   int8_t GetAttributeRenamedTo(ErrorResult&);
   void SetAttributeRenamedTo(int8_t, ErrorResult&);
 
   // Dictionary tests
   void PassDictionary(const Dict&, ErrorResult&);
+  void PassOptionalDictionary(const Optional<Dict>&, ErrorResult&);
+  void PassNullableDictionary(const Nullable<Dict>&, ErrorResult&);
+  void PassOptionalNullableDictionary(const Optional<Nullable<Dict> >&, ErrorResult&);
   void PassOtherDictionary(const GrandparentDict&, ErrorResult&);
   void PassSequenceOfDictionaries(const Sequence<Dict>&, ErrorResult&);
-  void PassDictionaryOrLong(const Dict&, ErrorResult&);
-  void PassDictionaryOrLong(int32_t, ErrorResult&);
 
   // Methods and properties imported via "implements"
   bool GetImplementedProperty(ErrorResult&);
   void SetImplementedProperty(bool, ErrorResult&);
   void ImplementedMethod(ErrorResult&);
   bool GetImplementedParentProperty(ErrorResult&);
   void SetImplementedParentProperty(bool, ErrorResult&);
   void ImplementedParentMethod(ErrorResult&);
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -256,21 +256,22 @@ interface TestInterface {
   //void passUnionWithDict((Dict or long) arg);
 
   // binaryNames tests
   void methodRenamedFrom();
   void methodRenamedFrom(byte argument);
   readonly attribute byte attributeGetterRenamedFrom;
   attribute byte attributeRenamedFrom;
 
-  void passDictionary(optional Dict x);
-  void passOtherDictionary(optional GrandparentDict x);
+  void passDictionary(Dict x);
+  void passOptionalDictionary(optional Dict x);
+  void passNullableDictionary(Dict? x);
+  void passOptionalNullableDictionary(optional Dict? x);
+  void passOtherDictionary(GrandparentDict x);
   void passSequenceOfDictionaries(sequence<Dict> x);
-  void passDictionaryOrLong(optional Dict x);
-  void passDictionaryOrLong(long x);
 };
 
 interface TestNonWrapperCacheInterface {
 };
 
 interface ImplementedInterfaceParent {
   void implementedParentMethod();
   attribute boolean implementedParentProperty;
--- a/dom/webidl/XMLHttpRequest.webidl
+++ b/dom/webidl/XMLHttpRequest.webidl
@@ -46,17 +46,17 @@ dictionary MozXMLHttpRequestParameters
   boolean mozAnon = false;
 
   /**
    * If true, the same origin policy will not be enforced on the request.
    */
   boolean mozSystem = false;
 };
 
-[Constructor(optional MozXMLHttpRequestParameters params)]
+[Constructor(optional MozXMLHttpRequestParameters? params = null)]
 interface XMLHttpRequest : XMLHttpRequestEventTarget {
   // event handler
   [TreatNonCallableAsNull, GetterInfallible=MainThread]
   attribute Function? onreadystatechange;
 
   // states
   const unsigned short UNSENT = 0;
   const unsigned short OPENED = 1;
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -1461,17 +1461,17 @@ XMLHttpRequest::_finalize(JSFreeOp* aFop
   ReleaseProxy(XHRIsGoingAway);
   XMLHttpRequestEventTarget::_finalize(aFop);
 }
 
 // static
 XMLHttpRequest*
 XMLHttpRequest::Constructor(JSContext* aCx,
                             JSObject* aGlobal,
-                            const MozXMLHttpRequestParametersWorkers& aParams,
+                            const Nullable<MozXMLHttpRequestParametersWorkers>& aParams,
                             ErrorResult& aRv)
 {
   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
   MOZ_ASSERT(workerPrivate);
 
   nsRefPtr<XMLHttpRequest> xhr = new XMLHttpRequest(aCx, workerPrivate);
 
   if (!Wrap(aCx, aGlobal, xhr)) {
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -67,17 +67,17 @@ public:
   virtual void
   _trace(JSTracer* aTrc) MOZ_OVERRIDE;
 
   virtual void
   _finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
 
   static XMLHttpRequest*
   Constructor(JSContext* aCx, JSObject* aGlobal,
-              const MozXMLHttpRequestParametersWorkers& aParams,
+              const Nullable<MozXMLHttpRequestParametersWorkers>& aParams,
               ErrorResult& aRv);
   void
   Unpin();
 
   bool
   Notify(JSContext* aCx, Status aStatus) MOZ_OVERRIDE;
 
 #define IMPL_GETTER_AND_SETTER(_type)                                          \