// Tests that IteratorClose is called in array destructuring patterns.

function test() {
    var returnCalled = 0;
    var returnCalledExpected = 0;
    var iterable = {};

    // empty [] calls IteratorClose regardless of "done" on the result.
    iterable[Symbol.iterator] = makeIterator({
        next: function() {
            return { done: true };
        },
        ret: function() {
            returnCalled++;
            return {};
        }
    });
    var [] = iterable;
    assertEq(returnCalled, ++returnCalledExpected);

    iterable[Symbol.iterator] = makeIterator({
        ret: function() {
            returnCalled++;
            return {};
        }
    });
    var [] = iterable;
    assertEq(returnCalled, ++returnCalledExpected);

    // Non-empty destructuring calls IteratorClose if iterator is not done by
    // the end of destructuring.
    var [a,b] = iterable;
    assertEq(returnCalled, ++returnCalledExpected);
    var [c,] = iterable;
    assertEq(returnCalled, ++returnCalledExpected);

    // throw in lhs ref calls IteratorClose
    function throwlhs() {
        throw "in lhs";
    }
    assertThrowsValue(function() {
        0, [...{}[throwlhs()]] = iterable;
    }, "in lhs");
    assertEq(returnCalled, ++returnCalledExpected);

    // throw in lhs ref calls IteratorClose with falsy "done".
    iterable[Symbol.iterator] = makeIterator({
        next: function() {
            // "done" is undefined.
            return {};
        },
        ret: function() {
            returnCalled++;
            return {};
        }
    });
    assertThrowsValue(function() {
        0, [...{}[throwlhs()]] = iterable;
    }, "in lhs");
    assertEq(returnCalled, ++returnCalledExpected);

    // throw in iter.next doesn't call IteratorClose
    iterable[Symbol.iterator] = makeIterator({
        next: function() {
            throw "in next";
        },
        ret: function() {
            returnCalled++;
            return {};
        }
    });
    assertThrowsValue(function() {
        var [d] = iterable;
    }, "in next");
    assertEq(returnCalled, returnCalledExpected);

    // "return" must return an Object.
    iterable[Symbol.iterator] = makeIterator({
        ret: function() {
            returnCalled++;
            return 42;
        }
    });
    assertThrowsInstanceOf(function() {
        var [] = iterable;
    }, TypeError);
    assertEq(returnCalled, ++returnCalledExpected);
}

test();

if (typeof reportCompare === "function")
    reportCompare(0, 0);
