Bug 1225392 part 2. WebIDL autogenerated iterators should chain up to %IteratorPrototype%. r=qdot
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 18 Nov 2015 18:26:07 -0500
changeset 273173 ff8e1e77c6151b0c94b9f9d8cf2b95b41030a5d5
parent 273172 0aff4d08702d9d8be59a02fbae60c98129ea432e
child 273174 2d24be34b7e2aa44a1c5edafb8eacef0cf625cef
push id68192
push userbzbarsky@mozilla.com
push dateWed, 18 Nov 2015 23:26:33 +0000
treeherdermozilla-inbound@ff8e1e77c615 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot
bugs1225392
milestone45.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 1225392 part 2. WebIDL autogenerated iterators should chain up to %IteratorPrototype%. r=qdot
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/test/test_iterable.html
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3280,16 +3280,23 @@ struct StrongPtrForMember
 
 inline
 JSObject*
 GetErrorPrototype(JSContext* aCx, JS::Handle<JSObject*> aForObj)
 {
   return JS_GetErrorPrototype(aCx);
 }
 
+inline
+JSObject*
+GetIteratorPrototype(JSContext* aCx, JS::Handle<JSObject*> aForObj)
+{
+  return JS_GetIteratorPrototype(aCx);
+}
+
 // Resolve an id on the given global object that wants to be included in
 // Exposed=System webidl annotations.  False return value means exception
 // thrown.
 bool SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
                          JS::Handle<jsid> id, bool* resolvedp);
 
 // Enumerate all ids on the given global object that wants to be included in
 // Exposed=System webidl annotations.  False return value means exception
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -575,16 +575,18 @@ def InterfacePrototypeObjectProtoGetter(
     if descriptor.hasNamedPropertiesObject:
         protoGetter = "GetNamedPropertiesObject"
         protoHandleGetter = None
     elif parentProtoName is None:
         if descriptor.interface.getExtendedAttribute("ArrayClass"):
             protoGetter = "JS_GetArrayPrototype"
         elif descriptor.interface.getExtendedAttribute("ExceptionClass"):
             protoGetter = "GetErrorPrototype"
+        elif descriptor.interface.isIteratorInterface():
+            protoGetter = "GetIteratorPrototype"
         else:
             protoGetter = "JS_GetObjectPrototype"
         protoHandleGetter = None
     else:
         prefix = toBindingNamespace(parentProtoName)
         protoGetter = prefix + "::GetProtoObject"
         protoHandleGetter = prefix + "::GetProtoObjectHandle"
 
@@ -2254,16 +2256,32 @@ class MethodDefiner(PropertyDefiner):
                 "name": "@@iterator",
                 "methodInfo": False,
                 "selfHostedName": "ArrayValues",
                 "length": 0,
                 "flags": "JSPROP_ENUMERATE",
                 "condition": MemberCondition(None, None)
             })
 
+        # Output an @@iterator for generated iterator interfaces.  This should
+        # not be necessary, but
+        # https://bugzilla.mozilla.org/show_bug.cgi?id=1091945 means that
+        # %IteratorPrototype%[@@iterator] is a broken puppy.
+        if (not static and
+            not unforgeable and
+            descriptor.interface.isIteratorInterface()):
+            self.regular.append({
+                "name": "@@iterator",
+                "methodInfo": False,
+                "selfHostedName": "IteratorIdentity",
+                "length": 0,
+                "flags": "0",
+                "condition": MemberCondition(None, None)
+            })
+
         # Generate the maplike/setlike iterator, if one wasn't already
         # generated by a method. If we already have an @@iterator symbol, fail.
         if descriptor.interface.maplikeOrSetlikeOrIterable:
             if hasIterator(methods, self.regular):
                 raise TypeError("Cannot have maplike/setlike/iterable interface with "
                                 "other members that generate @@iterator "
                                 "on interface %s, such as indexed getters "
                                 "or aliased functions." %
--- a/dom/bindings/test/test_iterable.html
+++ b/dom/bindings/test/test_iterable.html
@@ -45,27 +45,38 @@
          }
        }
 
        var itr;
        // Simple single type iterable creation and functionality test
        info("IterableSingle: Testing simple iterable creation and functionality");
        itr = new TestInterfaceIterableSingle();
        testExistence("IterableSingle: ", itr, base_properties);
+       var keys = [...itr.keys()];
+       var values = [...itr.values()];
+       var entries = [...itr.entries()];
        var key_itr = itr.keys();
        var value_itr = itr.values();
        var entries_itr = itr.entries();
        for (var i = 0; i < 3; ++i) {
          var key = key_itr.next();
          var value = value_itr.next();
          var entry = entries_itr.next();
          is(key.value, i, "IterableSingle: Key iterator value should be " + i);
+         is(key.value, keys[i],
+            "IterableSingle: Key iterator value should match destructuring " + i);
          is(value.value, key.value, "IterableSingle: Value iterator value should be " + key.value);
+         is(value.value, values[i],
+            "IterableSingle: Value iterator value should match destructuring " + i);
          is(entry.value[0], i, "IterableSingle: Entry iterator value 0 should be " + i);
          is(entry.value[1], i, "IterableSingle: Entry iterator value 1 should be " + i);
+         is(entry.value[0], entries[i][0],
+            "IterableSingle: Entry iterator value 0 should match destructuring " + i);
+         is(entry.value[1], entries[i][1],
+            "IterableSingle: Entry iterator value 1 should match destructuring " + i);
        }
        var key = key_itr.next();
        var value = value_itr.next();
        var entry = entries_itr.next();
        is(key.value, undefined, "IterableSingle: Key iterator value should be undefined");
        is(key.done, true, "IterableSingle: Key iterator done should be true");
        is(value.value, undefined, "IterableSingle: Value iterator value should be undefined");
        is(value.done, true, "IterableSingle: Value iterator done should be true");
@@ -75,27 +86,38 @@
           "[object TestInterfaceIterableSingleIteratorPrototype]",
           "iterator prototype should have the right brand");
 
        // Simple dual type iterable creation and functionality test
        info("IterableDouble: Testing simple iterable creation and functionality");
        itr = new TestInterfaceIterableDouble();
        testExistence("IterableDouble: ", itr, base_properties);
        var elements = [["a", "b"], ["c", "d"], ["e", "f"]]
+       var keys = [...itr.keys()];
+       var values = [...itr.values()];
+       var entries = [...itr.entries()];
        var key_itr = itr.keys();
        var value_itr = itr.values();
        var entries_itr = itr.entries();
        for (var i = 0; i < 3; ++i) {
          var key = key_itr.next();
          var value = value_itr.next();
          var entry = entries_itr.next();
          is(key.value, elements[i][0], "IterableDouble: Key iterator value should be " + elements[i][0]);
+         is(key.value, keys[i],
+            "IterableDouble: Key iterator value should match destructuring " + i);
          is(value.value, elements[i][1], "IterableDouble: Value iterator value should be " + elements[i][1]);
+         is(value.value, values[i],
+            "IterableDouble: Value iterator value should match destructuring " + i);
          is(entry.value[0], elements[i][0], "IterableDouble: Entry iterator value 0 should be " + elements[i][0]);
          is(entry.value[1], elements[i][1], "IterableDouble: Entry iterator value 1 should be " + elements[i][1]);
+         is(entry.value[0], entries[i][0],
+            "IterableDouble: Entry iterator value 0 should match destructuring " + i);
+         is(entry.value[1], entries[i][1],
+            "IterableDouble: Entry iterator value 1 should match destructuring " + i);
        }
        var key = key_itr.next();
        var value = value_itr.next();
        var entry = entries_itr.next()
        is(key.value, undefined, "IterableDouble: Key iterator value should be undefined");
        is(key.done, true, "IterableDouble: Key iterator done should be true");
        is(value.value, undefined, "IterableDouble: Value iterator value should be undefined");
        is(value.done, true, "IterableDouble: Value iterator done should be true");