From d81d165c25fcf230edbfc3a372fed54ee04e5a79 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Mon, 5 Sep 2022 15:27:11 +0000 Subject: [PATCH] Bug 1781730 - Support optional arguments in async iterable declarations. r=edgar Differential Revision: https://phabricator.services.mozilla.com/D155422 --- dom/bindings/Codegen.py | 15 +- dom/bindings/moz.build | 2 + dom/bindings/parser/WebIDL.py | 30 ++-- .../test_interface_maplikesetlikeiterable.py | 143 ++++++++++++++++++ .../test/TestInterfaceAsyncIterableSingle.cpp | 23 ++- .../test/TestInterfaceAsyncIterableSingle.h | 24 ++- ...stInterfaceAsyncIterableSingleWithArgs.cpp | 59 ++++++++ ...TestInterfaceAsyncIterableSingleWithArgs.h | 40 +++++ dom/bindings/test/test_async_iterable.html | 42 ++--- ...stInterfaceJSMaplikeSetlikeIterable.webidl | 13 ++ 10 files changed, 345 insertions(+), 46 deletions(-) create mode 100644 dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.cpp create mode 100644 dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.h diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 76929a2d6a68..4fd5696b07c9 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -9519,6 +9519,7 @@ class CGPerSignatureCall(CGThing): descriptor, idlNode.maplikeOrSetlikeOrIterable, idlNode.identifier.name, + self.getArgumentNames(), ) ) elif idlNode.isAttr() and idlNode.type.isObservableArray(): @@ -9602,8 +9603,11 @@ class CGPerSignatureCall(CGThing): self.cgRoot = CGList(cgThings) + def getArgumentNames(self): + return ["arg" + str(i) for i in range(len(self.arguments))] + def getArguments(self): - return [(a, "arg" + str(i)) for i, a in enumerate(self.arguments)] + return list(zip(self.arguments, self.getArgumentNames())) def processWebExtensionStubAttribute(self, idlNode, cgThings): nativeMethodName = "CallWebExtMethod" @@ -22107,8 +22111,10 @@ class CGIterableMethodGenerator(CGGeneric): using CGCallGenerator. """ - def __init__(self, descriptor, iterable, methodName): + def __init__(self, descriptor, iterable, methodName, args): if methodName == "forEach": + assert len(args) == 2 + CGGeneric.__init__( self, fill( @@ -22144,6 +22150,8 @@ class CGIterableMethodGenerator(CGGeneric): return if descriptor.interface.isIterable(): + assert len(args) == 0 + binding = descriptor.interface.identifier.name + "Iterator_Binding" init = "" else: @@ -22154,12 +22162,13 @@ class CGIterableMethodGenerator(CGGeneric): """ { ErrorResult initError; - self->InitAsyncIterator(result.get(), initError); + self->InitAsyncIterator(result.get(), ${args}initError); if (initError.MaybeSetPendingException(cx, "Asynchronous iterator initialization steps for ${ifaceName} failed")) { return false; } } """, + args="".join(a + ", " for a in args), ifaceName=descriptor.interface.identifier.name, ) CGGeneric.__init__( diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build index beb12c0fcd19..f581134dda50 100644 --- a/dom/bindings/moz.build +++ b/dom/bindings/moz.build @@ -132,6 +132,7 @@ if CONFIG["MOZ_DEBUG"] and CONFIG["ENABLE_TESTS"]: "test/TestInterfaceAsyncIterableDouble.h", "test/TestInterfaceAsyncIterableDoubleUnion.h", "test/TestInterfaceAsyncIterableSingle.h", + "test/TestInterfaceAsyncIterableSingleWithArgs.h", "test/TestInterfaceIterableDouble.h", "test/TestInterfaceIterableDoubleUnion.h", "test/TestInterfaceIterableSingle.h", @@ -150,6 +151,7 @@ if CONFIG["MOZ_DEBUG"] and CONFIG["ENABLE_TESTS"]: "test/TestInterfaceAsyncIterableDouble.cpp", "test/TestInterfaceAsyncIterableDoubleUnion.cpp", "test/TestInterfaceAsyncIterableSingle.cpp", + "test/TestInterfaceAsyncIterableSingleWithArgs.cpp", "test/TestInterfaceIterableDouble.cpp", "test/TestInterfaceIterableDoubleUnion.cpp", "test/TestInterfaceIterableSingle.cpp", diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 824d99e0fc60..a0c060faa714 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -13,6 +13,7 @@ import math import string from collections import defaultdict, OrderedDict from itertools import chain +import copy # Machinery @@ -4723,7 +4724,7 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): # Iterable adds ES6 iterator style functions and traits # (keys/values/entries/@@iterator) to an interface. class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase): - def __init__(self, location, identifier, keyType, valueType=None, scope=None): + def __init__(self, location, identifier, keyType, valueType, scope): IDLMaplikeOrSetlikeOrIterableBase.__init__( self, location, @@ -4798,9 +4799,15 @@ class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase): class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase): - def __init__( - self, location, identifier, keyType, valueType=None, argList=None, scope=None - ): + def __init__(self, location, identifier, keyType, valueType, argList, scope): + for arg in argList: + if not arg.optional: + raise WebIDLError( + "The arguments of the asynchronously iterable declaration on " + "%s must all be optional arguments." % identifier, + [arg.location], + ) + IDLMaplikeOrSetlikeOrIterableBase.__init__( self, location, @@ -4812,10 +4819,6 @@ class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase): ) self.iteratorType = None self.argList = argList - if argList is not None: - raise WebIDLError( - "Arguments of async iterable are not supported yet. Please reference Bug 1781730." - ) def __str__(self): return "declared async iterable with key '%s' and value '%s'" % ( @@ -4835,6 +4838,7 @@ class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase): members, False, self.iteratorType, + self.argList, affectsNothing=True, newObject=True, isIteratorAlias=(not self.isPairIterator()), @@ -4844,12 +4848,17 @@ class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase): if not self.isPairIterator(): return + # Methods can't share their IDLArguments, so we need to make copies here. + def copyArgList(argList): + return map(copy.copy, argList) + # object entries() self.addMethod( "entries", members, False, self.iteratorType, + copyArgList(self.argList), affectsNothing=True, newObject=True, isIteratorAlias=True, @@ -4860,6 +4869,7 @@ class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase): members, False, self.iteratorType, + copyArgList(self.argList), affectsNothing=True, newObject=True, ) @@ -7753,11 +7763,11 @@ class Parser(Tokenizer): elif len(p) == 9: keyType = p[4] valueType = p[6] - argList = None + argList = [] else: keyType = None valueType = p[4] - argList = None + argList = [] p[0] = IDLAsyncIterable( location, identifier, keyType, valueType, argList, self.globalScope() diff --git a/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py b/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py index 07fc8c5d7249..a83743a6b285 100644 --- a/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py +++ b/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py @@ -89,10 +89,18 @@ def WebIDLTest(parser, harness): # __iterable to it for the iterable<> case. iterableMembers.append(("__iterable", WebIDL.IDLIterable)) + asyncIterableMembers = [ + (x, WebIDL.IDLMethod) for x in ["entries", "keys", "values"] + ] + asyncIterableMembers.append(("__iterable", WebIDL.IDLAsyncIterable)) + valueIterableMembers = [("__iterable", WebIDL.IDLIterable)] valueIterableMembers.append(("__indexedgetter", WebIDL.IDLMethod)) valueIterableMembers.append(("length", WebIDL.IDLAttribute)) + valueAsyncIterableMembers = [("__iterable", WebIDL.IDLAsyncIterable)] + valueAsyncIterableMembers.append(("values", WebIDL.IDLMethod)) + disallowedIterableNames = ["keys", "entries", "values"] disallowedMemberNames = ["forEach", "has", "size"] + disallowedIterableNames mapDisallowedMemberNames = ["get"] + disallowedMemberNames @@ -169,6 +177,94 @@ def WebIDLTest(parser, harness): numProductions=3, ) + shouldPass( + "Async iterable (key only)", + """ + interface Foo1 { + async iterable; + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, + valueAsyncIterableMembers + unrelatedMembers, + # numProductions == 2 because of the generated iterator iface, + numProductions=2, + ) + + shouldPass( + "Async iterable (key only) inheriting from parent", + """ + interface Foo1 : Foo2 { + async iterable; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, + valueAsyncIterableMembers, + # numProductions == 3 because of the generated iterator iface, + numProductions=3, + ) + + shouldPass( + "Async iterable with argument (key only)", + """ + interface Foo1 { + async iterable(optional long foo); + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, + valueAsyncIterableMembers + unrelatedMembers, + # numProductions == 2 because of the generated iterator iface, + numProductions=2, + ) + + shouldPass( + "Async iterable (key and value)", + """ + interface Foo1 { + async iterable; + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, + asyncIterableMembers + unrelatedMembers, + # numProductions == 2 because of the generated iterator iface, + numProductions=2, + ) + + shouldPass( + "Async iterable (key and value) inheriting from parent", + """ + interface Foo1 : Foo2 { + async iterable; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, + asyncIterableMembers, + # numProductions == 3 because of the generated iterator iface, + numProductions=3, + ) + + shouldPass( + "Async iterable with argument (key and value)", + """ + interface Foo1 { + async iterable(optional long foo); + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, + asyncIterableMembers + unrelatedMembers, + # numProductions == 2 because of the generated iterator iface, + numProductions=2, + ) + shouldPass( "Maplike (readwrite)", """ @@ -373,6 +469,53 @@ def WebIDLTest(parser, harness): """, ) + shouldFail( + "Two iterables on same interface", + """ + interface Foo1 { + iterable; + async iterable; + }; + """, + ) + + shouldFail( + "Two iterables on same interface", + """ + interface Foo1 { + async iterable; + async iterable; + }; + """, + ) + + shouldFail( + "Async iterable with non-optional arguments", + """ + interface Foo1 { + async iterable(long foo); + }; + """, + ) + + shouldFail( + "Async iterable with non-optional arguments", + """ + interface Foo1 { + async iterable(optional long foo, long bar); + }; + """, + ) + + shouldFail( + "Async iterable with non-optional arguments", + """ + interface Foo1 { + async iterable(long foo); + }; + """, + ) + shouldFail( "Two maplike/setlikes in partials", """ diff --git a/dom/bindings/test/TestInterfaceAsyncIterableSingle.cpp b/dom/bindings/test/TestInterfaceAsyncIterableSingle.cpp index 540dd8605de9..2baa9286da44 100644 --- a/dom/bindings/test/TestInterfaceAsyncIterableSingle.cpp +++ b/dom/bindings/test/TestInterfaceAsyncIterableSingle.cpp @@ -59,7 +59,7 @@ void TestInterfaceAsyncIterableSingle::InitAsyncIterator(Iterator* aIterator, return; } - UniquePtr data(new IteratorData(0)); + UniquePtr data(new IteratorData(0, 1)); aIterator->SetData((void*)data.release()); } @@ -71,21 +71,31 @@ void TestInterfaceAsyncIterableSingle::DestroyAsyncIterator( already_AddRefed TestInterfaceAsyncIterableSingle::GetNextPromise( JSContext* aCx, Iterator* aIterator, ErrorResult& aRv) { + return GetNextPromise(aCx, aIterator, + reinterpret_cast(aIterator->GetData()), + aRv); +} + +already_AddRefed TestInterfaceAsyncIterableSingle::GetNextPromise( + JSContext* aCx, IterableIteratorBase* aIterator, IteratorData* aData, + ErrorResult& aRv) { RefPtr promise = Promise::Create(mParent->AsGlobal(), aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } - auto* data = reinterpret_cast(aIterator->GetData()); - data->mPromise = promise; + aData->mPromise = promise; NS_DispatchToMainThread(NS_NewRunnableFunction( "TestInterfaceAsyncIterableSingle::GetNextPromise", - [data, self = RefPtr{this}] { self->ResolvePromise(data); })); + [iterator = RefPtr{aIterator}, aData, self = RefPtr{this}] { + self->ResolvePromise(iterator, aData); + })); return promise.forget(); } -void TestInterfaceAsyncIterableSingle::ResolvePromise(IteratorData* aData) { +void TestInterfaceAsyncIterableSingle::ResolvePromise( + IterableIteratorBase* aIterator, IteratorData* aData) { AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(mParent))) { return; @@ -96,7 +106,8 @@ void TestInterfaceAsyncIterableSingle::ResolvePromise(IteratorData* aData) { iterator_utils::ResolvePromiseForFinished(cx, aData->mPromise, rv); } else { JS::Rooted value(cx); - Unused << ToJSValue(cx, (int32_t)(aData->mIndex * 9 % 7), &value); + Unused << ToJSValue( + cx, (int32_t)(aData->mIndex * 9 % 7 * aData->mMultiplier), &value); iterator_utils::ResolvePromiseWithKeyOrValue(cx, aData->mPromise, value, rv); diff --git a/dom/bindings/test/TestInterfaceAsyncIterableSingle.h b/dom/bindings/test/TestInterfaceAsyncIterableSingle.h index c22227eb2532..6687d2bbbe89 100644 --- a/dom/bindings/test/TestInterfaceAsyncIterableSingle.h +++ b/dom/bindings/test/TestInterfaceAsyncIterableSingle.h @@ -25,14 +25,14 @@ struct TestInterfaceAsyncIterableSingleOptions; // Implementation of test binding for webidl iterable interfaces, using // primitives for value type -class TestInterfaceAsyncIterableSingle final : public nsISupports, - public nsWrapperCache { +class TestInterfaceAsyncIterableSingle : public nsISupports, + public nsWrapperCache { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TestInterfaceAsyncIterableSingle) - TestInterfaceAsyncIterableSingle(nsPIDOMWindowInner* aParent, - bool aFailToInit); + explicit TestInterfaceAsyncIterableSingle(nsPIDOMWindowInner* aParent, + bool aFailToInit = false); nsPIDOMWindowInner* GetParentObject() const; virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; @@ -46,9 +46,10 @@ class TestInterfaceAsyncIterableSingle final : public nsISupports, already_AddRefed GetNextPromise(JSContext* aCx, Iterator* aIterator, ErrorResult& aRv); - private: + protected: struct IteratorData { - explicit IteratorData(int32_t aIndex) : mIndex(aIndex) {} + IteratorData(int32_t aIndex, uint32_t aMultiplier) + : mIndex(aIndex), mMultiplier(aMultiplier) {} ~IteratorData() { if (mPromise) { mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); @@ -57,9 +58,18 @@ class TestInterfaceAsyncIterableSingle final : public nsISupports, } RefPtr mPromise; uint32_t mIndex; + uint32_t mMultiplier; }; + + already_AddRefed GetNextPromise(JSContext* aCx, + IterableIteratorBase* aIterator, + IteratorData* aData, + ErrorResult& aRv); + virtual ~TestInterfaceAsyncIterableSingle() = default; - void ResolvePromise(IteratorData* aData); + + private: + void ResolvePromise(IterableIteratorBase* aIterator, IteratorData* aData); nsCOMPtr mParent; bool mFailToInit; diff --git a/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.cpp b/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.cpp new file mode 100644 index 000000000000..aa8f61b094fe --- /dev/null +++ b/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.cpp @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "mozilla/dom/TestInterfaceAsyncIterableSingleWithArgs.h" +#include "mozilla/dom/TestInterfaceJSMaplikeSetlikeIterableBinding.h" +#include "nsPIDOMWindow.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/IterableIterator.h" + +namespace mozilla::dom { + +// static +already_AddRefed +TestInterfaceAsyncIterableSingleWithArgs::Constructor( + const GlobalObject& aGlobal, ErrorResult& aRv) { + nsCOMPtr window = + do_QueryInterface(aGlobal.GetAsSupports()); + if (!window) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + RefPtr r = + new TestInterfaceAsyncIterableSingleWithArgs(window); + return r.forget(); +} + +JSObject* TestInterfaceAsyncIterableSingleWithArgs::WrapObject( + JSContext* aCx, JS::Handle aGivenProto) { + return TestInterfaceAsyncIterableSingleWithArgs_Binding::Wrap(aCx, this, + aGivenProto); +} + +void TestInterfaceAsyncIterableSingleWithArgs::InitAsyncIterator( + Iterator* aIterator, const TestInterfaceAsyncIteratorOptions& aOptions, + ErrorResult& aError) { + UniquePtr data(new IteratorData(0, aOptions.mMultiplier)); + aIterator->SetData((void*)data.release()); +} + +void TestInterfaceAsyncIterableSingleWithArgs::DestroyAsyncIterator( + Iterator* aIterator) { + auto* data = reinterpret_cast(aIterator->GetData()); + delete data; +} + +already_AddRefed +TestInterfaceAsyncIterableSingleWithArgs::GetNextPromise(JSContext* aCx, + Iterator* aIterator, + ErrorResult& aRv) { + return TestInterfaceAsyncIterableSingle::GetNextPromise( + aCx, aIterator, reinterpret_cast(aIterator->GetData()), + aRv); +} + +} // namespace mozilla::dom diff --git a/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.h b/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.h new file mode 100644 index 000000000000..30d7b8455b6c --- /dev/null +++ b/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_dom_TestInterfaceAsyncIterableSingleWithArgs_h +#define mozilla_dom_TestInterfaceAsyncIterableSingleWithArgs_h + +#include "mozilla/dom/TestInterfaceAsyncIterableSingle.h" + +namespace mozilla::dom { + +struct TestInterfaceAsyncIteratorOptions; + +// Implementation of test binding for webidl iterable interfaces, using +// primitives for value type +class TestInterfaceAsyncIterableSingleWithArgs final + : public TestInterfaceAsyncIterableSingle { + public: + using TestInterfaceAsyncIterableSingle::TestInterfaceAsyncIterableSingle; + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + static already_AddRefed Constructor( + const GlobalObject& aGlobal, ErrorResult& rv); + + using Iterator = + AsyncIterableIterator; + void InitAsyncIterator(Iterator* aIterator, + const TestInterfaceAsyncIteratorOptions& aOptions, + ErrorResult& aError); + void DestroyAsyncIterator(Iterator* aIterator); + + already_AddRefed GetNextPromise(JSContext* aCx, Iterator* aIterator, + ErrorResult& aRv); +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_TestInterfaceAsyncIterableSingleWithArgs_h diff --git a/dom/bindings/test/test_async_iterable.html b/dom/bindings/test/test_async_iterable.html index 8d7e77ece7ed..03af2097a5e7 100644 --- a/dom/bindings/test/test_async_iterable.html +++ b/dom/bindings/test/test_async_iterable.html @@ -14,6 +14,19 @@ add_task(async function init() { await SpecialPowers.pushPrefEnv({set: [["dom.expose_test_interfaces", true]]}); }); +async function check_single_result(itr, multiplier = 1) { + let values = []; + for await (let v of itr) { + values.push(v); + } + is(values.length, 10, `AsyncIterableSingle: should returns 10 elements`); + for (let i = 0; i < 10; i++) { + let expected = i * 9 % 7 * multiplier; + is(values[i], expected, + `AsyncIterableSingle: should be ${expected}, get ${values[i]}`); + } +} + async function test_data_single() { info(`AsyncIterableSingle: Testing simple iterable creation and functionality`); @@ -35,27 +48,16 @@ async function test_data_single() { is(itr.values, itr[Symbol.asyncIterator], `AsyncIterableSingle: Should be using @@asyncIterator for 'values'`); - let values = []; - for await (let v of itr) { - values.push(v); - } - is(values.length, 10, `AsyncIterableSingle: should returns 10 elements`); - for (let i = 0; i < 10; i++) { - let expected = i * 9 % 7; - is(values[i], i * 9 % 7, - `AsyncIterableSingle: should be ${expected}, get ${values[i]}`); - } + await check_single_result(itr); + await check_single_result(itr.values()); - values = []; - for await (let v of itr.values()) { - values.push(v); - } - is(values.length, 10, `AsyncIterableSingle: should returns 10 elements`); - for (let i = 0; i < 10; i++) { - let expected = i * 9 % 7; - is(values[i], i * 9 % 7, - `AsyncIterableSingle: should be ${expected}, get ${values[i]}`); - } + // eslint-disable-next-line no-undef + itr = new TestInterfaceAsyncIterableSingleWithArgs(); + is(itr.values, itr[Symbol.asyncIterator], + `AsyncIterableSingleWithArgs: Should be using @@asyncIterator for 'values'`); + + await check_single_result(itr, 1); + await check_single_result(itr.values({ multiplier: 2 }), 2); } async function test_data_double() { diff --git a/dom/webidl/TestInterfaceJSMaplikeSetlikeIterable.webidl b/dom/webidl/TestInterfaceJSMaplikeSetlikeIterable.webidl index f2570fc5db3e..1aae2435d621 100644 --- a/dom/webidl/TestInterfaceJSMaplikeSetlikeIterable.webidl +++ b/dom/webidl/TestInterfaceJSMaplikeSetlikeIterable.webidl @@ -109,6 +109,19 @@ interface TestInterfaceAsyncIterableSingle { async iterable; }; +dictionary TestInterfaceAsyncIteratorOptions { + unsigned long multiplier = 1; +}; + +[Pref="dom.expose_test_interfaces", + Exposed=Window] +interface TestInterfaceAsyncIterableSingleWithArgs { + [Throws] + constructor(); + + async iterable(optional TestInterfaceAsyncIteratorOptions options = {}); +}; + [Pref="dom.expose_test_interfaces", Exposed=Window] interface TestInterfaceAsyncIterableDouble {