Bug 1215755. Change the Web IDL parser to just put a next() method in iterator interfaces instead of using an additional IterableIterator interface. Fix up the other test failures in test_interface_maplikesetlikeiterable.py while I'm here. r=qdot
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 19 Oct 2015 20:17:39 -0400
changeset 289154 a711f68848964a268dc6dd77faddb0d2d984571e
parent 289153 669a973d69d733e91abfa2898316e21ff61d7cea
child 289155 c1a68835d0847e3c225cc4602efd4df686fd60b1
push id5392
push userraliiev@mozilla.com
push dateMon, 14 Dec 2015 20:08:23 +0000
treeherdermozilla-esr52@16ce8562a975 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot
bugs1215755
milestone44.0a1
Bug 1215755. Change the Web IDL parser to just put a next() method in iterator interfaces instead of using an additional IterableIterator interface. Fix up the other test failures in test_interface_maplikesetlikeiterable.py while I'm here. r=qdot
dom/bindings/Bindings.conf
dom/bindings/parser/WebIDL.py
dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py
dom/webidl/IterableIterator.webidl
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -695,20 +695,16 @@ DOMInterfaces = {
     'wrapperCache': False,
 },
 
 'InputStream': {
     'nativeType': 'nsIInputStream',
     'notflattened': True
 },
 
-'IterableIterator': {
-    'skipGen': True
-},
-
 'KeyEvent': {
     'concrete': False
 },
 
 'LegacyMozTCPSocket': {
     'headerFile': 'TCPSocket.h',
     'wrapperCache': False,
 },
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -735,17 +735,17 @@ class IDLInterface(IDLObjectWithScope, I
                 # Check that we only have one interface declaration (currently
                 # there can only be one maplike/setlike declaration per
                 # interface)
                 if self.maplikeOrSetlikeOrIterable:
                     raise WebIDLError("%s declaration used on "
                                       "interface that already has %s "
                                       "declaration" %
                                       (member.maplikeOrSetlikeOrIterableType,
-                                       self.maplikeOrSetlike.maplikeOrSetlikeOrIterableType),
+                                       self.maplikeOrSetlikeOrIterable.maplikeOrSetlikeOrIterableType),
                                       [self.maplikeOrSetlikeOrIterable.location,
                                        member.location])
                 self.maplikeOrSetlikeOrIterable = member
                 # If we've got a maplike or setlike declaration, we'll be building all of
                 # our required methods in Codegen. Generate members now.
                 self.maplikeOrSetlikeOrIterable.expand(self.members, self.isJSImplemented())
 
         # Now that we've merged in our partial interfaces, set the
@@ -6562,54 +6562,52 @@ class Parser(Tokenizer):
         self._filename = None
 
     def finish(self):
         # If we have interfaces that are iterable, create their
         # iterator interfaces and add them to the productions array.
         interfaceStatements = [p for p in self._productions if
                                isinstance(p, IDLInterface)]
 
+        iterableIteratorIface = None
         for iface in interfaceStatements:
             iterable = None
             # We haven't run finish() on the interface yet, so we don't know
             # whether our interface is maplike/setlike/iterable or not. This
             # means we have to loop through the members to see if we have an
             # iterable member.
             for m in iface.members:
                 if isinstance(m, IDLIterable):
                     iterable = m
                     break
             if iterable:
+                def simpleExtendedAttr(str):
+                    return IDLExtendedAttribute(iface.location, (str, ))
+                nextMethod = IDLMethod(
+                    iface.location,
+                    IDLUnresolvedIdentifier(iface.location, "next"),
+                    BuiltinTypes[IDLBuiltinType.Types.object], [])
+                nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")])
                 itr_ident = IDLUnresolvedIdentifier(iface.location,
                                                     iface.identifier.name + "Iterator")
                 itr_iface = IDLInterface(iface.location, self.globalScope(),
-                                         itr_ident, None, [],
+                                         itr_ident, None, [nextMethod],
                                          isKnownNonPartial=True)
-                itr_iface.addExtendedAttributes([IDLExtendedAttribute(iface.location,
-                                                                      ("NoInterfaceObject", ))])
+                itr_iface.addExtendedAttributes([simpleExtendedAttr("NoInterfaceObject")])
                 # Make sure the exposure set for the iterator interface is the
                 # same as the exposure set for the iterable interface, because
                 # we're going to generate methods on the iterable that return
                 # instances of the iterator.
                 itr_iface._exposureGlobalNames = set(iface._exposureGlobalNames)
-                # Always append generated iterable interfaces and their
-                # matching implements statements after the interface they're a
-                # member of, otherwise nativeType generation won't work
-                # correctly.
+                # Always append generated iterable interfaces after the
+                # interface they're a member of, otherwise nativeType generation
+                # won't work correctly.
                 itr_iface.iterableInterface = iface
                 self._productions.append(itr_iface)
                 iterable.iteratorType = IDLWrapperType(iface.location, itr_iface)
-                itrPlaceholder = IDLIdentifierPlaceholder(iface.location,
-                                                          IDLUnresolvedIdentifier(iface.location,
-                                                                                  "IterableIterator"))
-                implements = IDLImplementsStatement(iface.location,
-                                                    IDLIdentifierPlaceholder(iface.location,
-                                                                             itr_ident),
-                                                    itrPlaceholder)
-                self._productions.append(implements)
 
         # Then, finish all the IDLImplementsStatements.  In particular, we
         # have to make sure we do those before we do the IDLInterfaces.
         # XXX khuey hates this bit and wants to nuke it from orbit.
         implementsStatements = [p for p in self._productions if
                                 isinstance(p, IDLImplementsStatement)]
         otherStatements = [p for p in self._productions if
                            not isinstance(p, IDLImplementsStatement)]
--- a/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py
+++ b/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py
@@ -5,100 +5,112 @@ def WebIDLTest(parser, harness):
     def shouldPass(prefix, iface, expectedMembers, numProductions=1):
         p = parser.reset()
         p.parse(iface)
         results = p.finish()
         harness.check(len(results), numProductions,
                       "%s - Should have production count %d" % (prefix, numProductions))
         harness.ok(isinstance(results[0], WebIDL.IDLInterface),
                    "%s - Should be an IDLInterface" % (prefix))
-        harness.check(len(results[0].members), len(expectedMembers),
-                      "%s - Should be %d members" % (prefix,
-                                                     len(expectedMembers)))
+        # Make a copy, since we plan to modify it
+        expectedMembers = list(expectedMembers)
         for m in results[0].members:
             name = m.identifier.name
             if (name, type(m)) in expectedMembers:
                 harness.ok(True, "%s - %s - Should be a %s" % (prefix, name,
                                                                type(m)))
-            elif isinstance(m, WebIDL.IDLMaplikeOrSetlike):
-                harness.ok(True, "%s - %s - Should be a MaplikeOrSetlike" %
-                           (prefix, name))
+                expectedMembers.remove((name, type(m)))
             else:
                 harness.ok(False, "%s - %s - Unknown symbol of type %s" %
                            (prefix, name, type(m)))
+        # A bit of a hoop because we can't generate the error string if we pass
+        if len(expectedMembers) == 0:
+            harness.ok(True, "Found all the members")
+        else:
+            harness.ok(False,
+                       "Expected member not found: %s of type %s" %
+                       (expectedMembers[0][0], expectedMembers[0][1]))
         return results
 
     def shouldFail(prefix, iface):
         try:
             p = parser.reset()
             p.parse(iface)
             p.finish()
             harness.ok(False,
                        prefix + " - Interface passed when should've failed")
         except WebIDL.WebIDLError, e:
             harness.ok(True,
                        prefix + " - Interface failed as expected")
         except Exception, e:
             harness.ok(False,
-                       prefix + " - Interface failed but not as a WebIDLError exception")
+                       prefix + " - Interface failed but not as a WebIDLError exception: %s" % e)
 
     iterableMembers = [(x, WebIDL.IDLMethod) for x in ["entries", "keys",
                                                        "values"]]
-    setROMembers = ([(x, WebIDL.IDLMethod) for x in ["has", "foreach"]] +
+    setROMembers = ([(x, WebIDL.IDLMethod) for x in ["has", "forEach"]] +
                     [("__setlike", WebIDL.IDLMaplikeOrSetlike)] +
                     iterableMembers)
     setROMembers.extend([("size", WebIDL.IDLAttribute)])
     setRWMembers = ([(x, WebIDL.IDLMethod) for x in ["add",
                                                      "clear",
                                                      "delete"]] +
                     setROMembers)
     setROChromeMembers = ([(x, WebIDL.IDLMethod) for x in ["__add",
                                                            "__clear",
                                                            "__delete"]] +
                           setROMembers)
     setRWChromeMembers = ([(x, WebIDL.IDLMethod) for x in ["__add",
                                                            "__clear",
                                                            "__delete"]] +
                           setRWMembers)
-    mapROMembers = ([(x, WebIDL.IDLMethod) for x in ["get", "has", "foreach"]] +
+    mapROMembers = ([(x, WebIDL.IDLMethod) for x in ["get", "has", "forEach"]] +
                     [("__maplike", WebIDL.IDLMaplikeOrSetlike)] +
                     iterableMembers)
     mapROMembers.extend([("size", WebIDL.IDLAttribute)])
     mapRWMembers = ([(x, WebIDL.IDLMethod) for x in ["set",
                                                      "clear",
                                                      "delete"]] + mapROMembers)
     mapRWChromeMembers = ([(x, WebIDL.IDLMethod) for x in ["__set",
                                                            "__clear",
                                                            "__delete"]] +
                           mapRWMembers)
 
+    # OK, now that we've used iterableMembers to set up the above, append
+    # __iterable to it for the iterable<> case.
+    iterableMembers.append(("__iterable", WebIDL.IDLIterable))
+
     disallowedIterableNames = ["keys", "entries", "values"]
     disallowedMemberNames = ["forEach", "has", "size"] + disallowedIterableNames
     mapDisallowedMemberNames = ["get"] + disallowedMemberNames
     disallowedNonMethodNames = ["clear", "delete"]
     mapDisallowedNonMethodNames = ["set"] + disallowedNonMethodNames
     setDisallowedNonMethodNames = ["add"] + disallowedNonMethodNames
 
     #
     # Simple Usage Tests
     #
 
     shouldPass("Iterable (key only)",
                """
                interface Foo1 {
                iterable<long>;
                };
-               """, iterableMembers)
+               """, iterableMembers,
+               # numProductions == 2 because of the generated iterator iface,
+               numProductions=2)
 
     shouldPass("Iterable (key and value)",
                """
                interface Foo1 {
                iterable<long, long>;
                };
-               """, iterableMembers)
+               """, iterableMembers,
+               # numProductions == 2 because of the generated iterator iface,
+               numProductions=2)
 
     shouldPass("Maplike (readwrite)",
                """
                interface Foo1 {
                maplike<long, long>;
                };
                """, mapRWMembers)
 
@@ -569,10 +581,10 @@ def WebIDLTest(parser, harness):
                    long delete(long a, long b, double c, double d);
                    };
                    """, mapRWMembers)
 
     for m in r[0].members:
         if m.identifier.name in ["clear", "set", "delete"]:
             harness.ok(m.isMethod(), "%s should be a method" % m.identifier.name)
             harness.check(m.maxArgCount, 4, "%s should have 4 arguments" % m.identifier.name)
-            harness.ok(not m.isMaplikeOrSetlikeMethod(),
+            harness.ok(not m.isMaplikeOrSetlikeOrIterableMethod(),
                        "%s should not be a maplike/setlike function" % m.identifier.name)
--- a/dom/webidl/IterableIterator.webidl
+++ b/dom/webidl/IterableIterator.webidl
@@ -1,22 +1,14 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-[NoInterfaceObject,
- Exposed=(Window,Worker,System)]
-interface IterableIterator
-{
-  [Throws]
-  object next();
-};
-
 dictionary IterableKeyOrValueResult {
   any value;
   boolean done = false;
 };
 
 dictionary IterableKeyAndValueResult {
   sequence<any> value = [];
   boolean done = false;