archives

« Bugzilla Issues Index

#4160 — Can GeneratorResumeAbrupt throw an exception?


25.3.3.4 GeneratorResumeAbrupt(generator, abruptCompletion)

Step 11 says: “Let _result_ be the value returned by the resumed computation.”

If you resume the computation and `abruptCompletion.[[type]]` is `throw`, is it possible that the resumed computation throws an exception? That would mean that GeneratorResumeAbrupt would throw an exception, right? Independently of the answers to these questions, I’d explain the effect of `throw` completions.


If fact, getting a throw completion back as result is the most common case.

Assume we have an active generator created like:

function * counter(n) {
while (true) yield n++
}
let g=counter(0);

And its consumer executes something like:

g.next(); //start the loop
g.throw("abort counting");

From the perspective of g, that will be equivalent to replacing the yield with the above throw. The exception will go all the way to the top counter's body eventually landing in step 4.1 of GeneratorStart with result being the throw completion record for "about counting". Step 4.7.b sends control back to GeneratorResumeAbrupt step 11 with that same throw completion record. That eventually returns to the g.throw call site, with the throw completion so the exception continues to propagate from there.

So, from there perspective of the client, in this case g.throw(...) was essentially equivalent to just saying: throw "abort counting"


Ah, good, thanks for confirming my suspicions.

For your example, I see a different control flow:

* Generator.prototype.throw (25.3.1.4)
* GeneratorResumeAbrupt (25.3.3.4)
* The state of the generator is "suspendedYield" (step 5ff)
* The part that I find a bit unclear is step 11 (of GeneratorResumeAbrupt): “Let _result_ be the value returned by the resumed computation.” It sounds like a value being returned is the normal case, but with `throw`, it isn’t. Therefore, I’d mention what happens if the “resumed computation” throws an exception. I’m assuming that that leads to GeneratorResumeAbrupt throwing an exception(?)


(In reply to Axel Rauschmayer from comment #2)

> * The part that I find a bit unclear is step 11 (of GeneratorResumeAbrupt):
> “Let _result_ be the value returned by the resumed computation.” It sounds
> like a value being returned is the normal case, but with `throw`, it isn’t.
> Therefore, I’d mention what happens if the “resumed computation” throws an
> exception. I’m assuming that that leads to GeneratorResumeAbrupt throwing an
> exception(?)

"value" in this case, is the completion record ([[type]] throw in this case) returned from the inner algorithm of 25.3.3.1.

That completion record is just returned as the completion record for GeneratorResumeAbrupt and execution proceeds as if the throw method had directly thrown the exception.

Note that in my example the exception represent by that completion record is the one injected via the throw method call. But if the yield was in the scope of a catch clause, the catch clause or other generator function code might have thrown a different exception. In that case the GeneratorResumeAbrupt completion record would reflect that other exception.


If it’s a completion then that resolves my confusion. How about s/value/completion/ in the following sentence? “Let _result_ be the value returned by the resumed computation.”

> Note that in my example the exception represent by that completion record is the one injected via the throw method call. But if the yield was in the scope of a catch clause, the catch clause or other generator function code might have thrown a different exception. In that case the GeneratorResumeAbrupt completion record would reflect that other exception.

Right. Due to `try-catch` (and `finally`), it wouldn’t even have to be an exception, the returned completion could have been created by a `return` or by a `yield`.


fixed in rev26 editor's draft


in rev36