google / google/closure-compiler

Call return() on the iterator when a for-of loop exits abruptly

Open
#2,958 2 comments 2 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
7.7k
Forks
1.2k
Avg merge
2d 12h
Merged PRs (30d)
6

Description

This breaks out one part of #2899.

I looked into this briefly today. In order to do it right, we end up bloating our for-of transpilation quite a bit. Currently we transpile

```js
for (var x of y) {
...
}
```

to

```js
for (var iter=$jscomp.makeIterator(y), key=iter.next(); !key.done; key=iter.next()) {
let x = key.value;
...
}
```

which isn't so bad. We can handle `break`, `continue`, and `return` pretty easily by inserting the `return` call immediately before each, and it doesn't cost anything if you don't use them. But `throw` can be invisible (i.e. it's likely not coming from a `THROW` node in the block's AST), so the only way to handle it correctly is to wrap the whole thing in a catch:

```js
for (var iter=$jscomp.makeIterator(y), key=iter.next(); !key.done; key=iter.next()) {
let x = key.value;
try {
...
} catch (e) {
if (iter.return) iter.return();
throw e;
}
}
```

Even this only gets most of the way there - if `return` throws then we end up with the wrong error thrown. To get that correct, we need an additional `try-finally` around the `return`. If we're dealing with `break`s as well, at this point, it probably makes sense to handle those at the same time, rather than mutating the AST inside the body:

```js
try {
for (var iter=$jscomp.makeIterator(y), key=iter.next(); !key.done; key=iter.next()) {
let x = key.value;
...
}
} catch (e) {
key.thrown = {thrown: e};
} finally {
try {
if (!key.done && iter.return) iter.return();
} finally {
if (key.thrown) throw key.thrown.thrown;
}
}
```

I estimate that this will add somewhere between 50 and 80 extra gzipped bytes to every for-of loop.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.