regenerator icon indicating copy to clipboard operation
regenerator copied to clipboard

yield* should call iterator's .return() even if .throw() is null

Open nicolo-ribaudo opened this issue 8 years ago • 0 comments

Consider this code:

const iterable = {
    [Symbol.iterator]: () => ({
        next: () => ({ value: 1 }),
        throw: undefined,
        return: () => ({ done: !console.log(".return()") })
    })
};

function* gf() {
    yield* iterable;
}

const it = gf();
console.log(it.next());
console.log(it.throw());

It correctly logs

> Object {value: 1}
> .return()
> Uncaught TypeError: Cannot read property 'call' of undefined

If I change throw: undefined to throw: null it should behave the same, but regenerator doesn't call the .return() method:

> Object {value: 1}
> Uncaught TypeError: Cannot read property 'call' of undefined

Specification:

14.4.14 Runtime Semantics: Evaluation
  ...
  YieldExpression : yield * AssignmentExpression
    ...
    6.b. Else if received.[[type]] is throw, then
        i. Let throw be GetMethod(iterator, "throw").
       ii. ReturnIfAbrupt(throw).
      iii. If throw is not undefined, then
            ...
      iv. Else,
        1. NOTE: If iterator does not have a throw method, this throw is going to terminate the yield* loop. But first we need to give iterator a chance to clean up.
        2. Let closeResult be IteratorClose(iterator, Completion{[[type]]: normal , [[value]]: empty, [[target]]:empty}).


7.3.9 GetMethod (O, P)
    1. Assert: IsPropertyKey(P) is true.
    2. Let func be GetV(O, P).
    3. ReturnIfAbrupt(func).
    4. If func is either undefined or null, return undefined.

If iterator.throw is null IteratorClose must be called, because GetMethod returns undefined

nicolo-ribaudo avatar Mar 25 '16 15:03 nicolo-ribaudo