Bug 1315135. Remove the RegExp (and some Date) special casing from our dictionary conversions and Web IDL overload resolution. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 23 Nov 2016 22:57:29 -0500
changeset 324150 83f951d60fc77f37d94f16926762dd5ed58b3494
parent 324149 3ba00502fa16601c4daafe041bb65e318e0b4be2
child 324151 d867784dbea4d023c43b94c92d47f965777ae367
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewerspeterv
bugs1315135
milestone53.0a1
Bug 1315135. Remove the RegExp (and some Date) special casing from our dictionary conversions and Web IDL overload resolution. r=peterv
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/parser/tests/test_distinguishability.py
dom/bindings/test/test_exception_messages.html
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -231,60 +231,20 @@ UnwrapObject(JSObject* obj, U& value, pr
 template <prototypes::ID PrototypeID, class T, typename U>
 MOZ_ALWAYS_INLINE nsresult
 UnwrapObject(JSObject* obj, U& value)
 {
   return UnwrapObject<T>(obj, value, PrototypeID,
                          PrototypeTraits<PrototypeID>::Depth);
 }
 
-inline bool
-IsNotDateOrRegExp(JSContext* cx, JS::Handle<JSObject*> obj,
-                  bool* notDateOrRegExp)
-{
-  MOZ_ASSERT(obj);
-
-  js::ESClass cls;
-  if (!js::GetBuiltinClass(cx, obj, &cls)) {
-    return false;
-  }
-
-  *notDateOrRegExp = cls != js::ESClass::Date && cls != js::ESClass::RegExp;
-  return true;
-}
-
 MOZ_ALWAYS_INLINE bool
-IsObjectValueConvertibleToDictionary(JSContext* cx,
-                                     JS::Handle<JS::Value> objVal,
-                                     bool* convertible)
+IsConvertibleToDictionary(JS::Handle<JS::Value> val)
 {
-  JS::Rooted<JSObject*> obj(cx, &objVal.toObject());
-  return IsNotDateOrRegExp(cx, obj, convertible);
-}
-
-MOZ_ALWAYS_INLINE bool
-IsConvertibleToDictionary(JSContext* cx, JS::Handle<JS::Value> val,
-                          bool* convertible)
-{
-  if (val.isNullOrUndefined()) {
-    *convertible = true;
-    return true;
-  }
-  if (!val.isObject()) {
-    *convertible = false;
-    return true;
-  }
-  return IsObjectValueConvertibleToDictionary(cx, val, convertible);
-}
-
-MOZ_ALWAYS_INLINE bool
-IsConvertibleToCallbackInterface(JSContext* cx, JS::Handle<JSObject*> obj,
-                                 bool* convertible)
-{
-  return IsNotDateOrRegExp(cx, obj, convertible);
+  return val.isNullOrUndefined() || val.isObject();
 }
 
 // The items in the protoAndIfaceCache are indexed by the prototypes::id::ID,
 // constructors::id::ID and namedpropertiesobjects::id::ID enums, in that order.
 // The end of the prototype objects should be the start of the interface
 // objects, and the end of the interface objects should be the start of the
 // named properties objects.
 static_assert((size_t)constructors::id::_ID_Start ==
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -5778,40 +5778,34 @@ def getJSToNativeConversionInfo(type, de
             }
             """,
             dictLoc=dictLoc,
             val=val,
             desc=firstCap(sourceDescription),
             exceptionCode=exceptionCode)
 
         if failureCode is not None:
-            if isDefinitelyObject:
-                dictionaryTest = "IsObjectValueConvertibleToDictionary"
-            else:
-                dictionaryTest = "IsConvertibleToDictionary"
-
-            template = fill("""
-                { // scope for isConvertible
-                  bool isConvertible;
-                  if (!${testConvertible}(cx, ${val}, &isConvertible)) {
-                    $*{exceptionCode}
-                  }
-                  if (!isConvertible) {
-                    $*{failureCode}
-                  }
-
-                  $*{conversionCode}
-                }
-
-                """,
-                testConvertible=dictionaryTest,
-                val=val,
-                exceptionCode=exceptionCode,
-                failureCode=failureCode,
-                conversionCode=conversionCode)
+            # This means we're part of an overload or union conversion, and
+            # should simply skip stuff if our value is not convertible to
+            # dictionary, instead of trying and throwing.  If we're either
+            # isDefinitelyObject or isNullOrUndefined then we're convertible to
+            # dictionary and don't need to check here.
+            if isDefinitelyObject or isNullOrUndefined:
+                template = conversionCode
+            else:
+                template = fill(
+                    """
+                    if (!IsConvertibleToDictionary(${val})) {
+                      $*{failureCode}
+                    }
+                    $*{conversionCode}
+                    """,
+                    val=val,
+                    failureCode=failureCode,
+                    conversionCode=conversionCode)
         else:
             template = conversionCode
 
         if type.nullable():
             declType = CGTemplatedType("Nullable", declType)
             template = CGIfElseWrapper("${val}.isNullOrUndefined()",
                                        CGGeneric("${declName}.SetNull();\n"),
                                        CGGeneric(template)).define()
@@ -8025,22 +8019,22 @@ class CGMethodCall(CGThing):
                 tryCall(nullOrUndefSigs[0], 2, isNullOrUndefined=True)
                 caseBody.append(CGGeneric("}\n"))
 
             # Now check for distinguishingArg being various kinds of objects.
             # The spec says to check for the following things in order:
             # 1)  A platform object that's not a platform array object, being
             #     passed to an interface or "object" arg.
             # 2)  A Date object being passed to a Date or "object" arg.
-            # 3)  A RegExp object being passed to a RegExp or "object" arg.
-            # 4)  A callable object being passed to a callback or "object" arg.
-            # 5)  An iterable object being passed to a sequence arg.
-            # 6)  Any non-Date and non-RegExp object being passed to a
-            #     array or callback interface or dictionary or
-            #     "object" arg.
+            #     XXXbz This is actually gone from the spec now, but we still
+            #     have some APIs using Date.
+            # 3)  A callable object being passed to a callback or "object" arg.
+            # 4)  An iterable object being passed to a sequence arg.
+            # 5)  Any object being passed to a array or callback interface or
+            #     dictionary or "object" arg.
 
             # First grab all the overloads that have a non-callback interface
             # (which includes typed arrays and arraybuffers) at the
             # distinguishing index.  We can also include the ones that have an
             # "object" here, since if those are present no other object-typed
             # argument will be.
             objectSigs = [
                 s for s in possibleSignatures
@@ -12586,24 +12580,18 @@ class CGDictionary(CGThing):
                   return false;
                 }
 
                 """,
                 dictName=self.makeClassName(self.dictionary.parent))
         else:
             body += dedent(
                 """
-                { // scope for isConvertible
-                  bool isConvertible;
-                  if (!IsConvertibleToDictionary(cx, val, &isConvertible)) {
-                    return false;
-                  }
-                  if (!isConvertible) {
-                    return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
-                  }
+                if (!IsConvertibleToDictionary(val)) {
+                  return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
                 }
 
                 """)
 
         memberInits = [self.getMemberConversion(m).define()
                        for m in self.memberInfo]
         if memberInits:
             body += fill(
--- a/dom/bindings/parser/tests/test_distinguishability.py
+++ b/dom/bindings/parser/tests/test_distinguishability.py
@@ -158,17 +158,18 @@ def WebIDLTest(parser, harness):
                  "CallbackInterface?", "CallbackInterface2",
                  "object", "Callback", "Callback2", "optional Dict",
                  "optional Dict2", "sequence<long>", "sequence<short>",
                  "MozMap<object>", "MozMap<Dict>", "MozMap<long>",
                  "Date", "Date?", "any",
                  "Promise<any>", "Promise<any>?",
                  "USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer",
                  "Uint8Array", "Uint16Array" ]
-    # When we can parse Date and RegExp, we need to add them here.
+    # When we can parse Date, we need to add it here.
+    # XXXbz we can, and should really do that...
 
     # 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 and
                 (a != "any" and a != "Promise<any>" and a != "Promise<any>?")]
     numerics = [ "long", "short", "long?", "short?" ]
     booleans = [ "boolean", "boolean?" ]
     primitives = numerics + booleans
--- a/dom/bindings/test/test_exception_messages.html
+++ b/dom/bindings/test/test_exception_messages.html
@@ -39,19 +39,19 @@ https://bugzilla.mozilla.org/show_bug.cg
         "Value being assigned to TreeWalker.currentNode does not implement interface Node.",
         "wrong interface setter call" ],
       [ 'document.createElement("canvas").getContext("2d").fill("bogus")',
         "Argument 1 of CanvasRenderingContext2D.fill 'bogus' is not a valid value for enumeration CanvasWindingRule.",
         "bogus enum value" ],
       [ 'document.createTreeWalker(document, 0xFFFFFFFF, { acceptNode: 5 }).nextNode()',
         "Property 'acceptNode' is not callable.",
         "non-callable callback interface operation property" ],
-      [ '(new TextDecoder).decode(new Uint8Array(), new RegExp())',
+      [ '(new TextDecoder).decode(new Uint8Array(), 5)',
         "Argument 2 of TextDecoder.decode can't be converted to a dictionary.",
-        "regexp passed for a dictionary" ],
+        "primitive passed for a dictionary" ],
       [ 'URL.createObjectURL(null, null)',
         "Argument 1 is not valid for any of the 2-argument overloads of URL.createObjectURL.",
         "overload resolution failure" ],
       [ 'document.createElement("select").add({})',
         "Argument 1 of HTMLSelectElement.add could not be converted to any of: HTMLOptionElement, HTMLOptGroupElement.",
         "invalid value passed for union" ],
       [ 'document.createElement("canvas").getContext("2d").createLinearGradient(0, 1, 0, 1).addColorStop(NaN, "")',
         "Argument 1 of CanvasGradient.addColorStop is not a finite floating-point value.",