Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using --downlevelIteration with nested loops results in incorrect error handling code #30083

Closed
tsznuk opened this issue Feb 25, 2019 · 1 comment · Fixed by #31519
Closed
Assignees
Labels
Bug A bug in TypeScript

Comments

@tsznuk
Copy link

tsznuk commented Feb 25, 2019

TypeScript Version: 3.4.0-dev.20190223

Search Terms:

downlevelIteration, nested loop

Code

for (const i of [0, 1, 2, 3, 4]) {
  try {
    for (const j of [1, 2, 3]) {
      if (i === 2) {
        throw new Error('ERR');
      }
    }
    console.log(i);
  } catch (err) {
    console.log('E %s %s', i, err);
  }
}

Expected behavior:

When compiled with --downlevelIteration and ran the code should output:

0
1
E 2 Error: ERR
3
4

Actual behavior:

Instead the output is:

0
1
E 2 Error: ERR
E 3 Error: ERR
E 4 Error: ERR

This can be explained by looking at the generated JS code:

var __values = (this && this.__values) || function (o) {
    var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
    if (m) return m.call(o);
    return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
};
var e_1, _a, e_2, _b;
try {
    for (var _c = __values([0, 1, 2, 3, 4]), _d = _c.next(); !_d.done; _d = _c.next()) {
        var i = _d.value;
        try {
            try {
                for (var _e = __values([1, 2, 3]), _f = _e.next(); !_f.done; _f = _e.next()) {
                    var j = _f.value;
                    if (i === 2) {
                        throw new Error('ERR');
                    }
                }
            }
            catch (e_2_1) { e_2 = { error: e_2_1 }; }
            finally {
                try {
                    if (_f && !_f.done && (_b = _e["return"])) _b.call(_e);
                }
                finally { if (e_2) throw e_2.error; }
            }
            console.log(i);
        }
        catch (err) {
            console.log('E %s %s', i, err);
        }
    }
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
    try {
        if (_d && !_d.done && (_a = _c["return"])) _a.call(_c);
    }
    finally { if (e_1) throw e_1.error; }
}

The e_2 variable is not cleared at the start of a loop, so the exception is rethrown in each subsequent iteration.

Note that compilation without --downlevelIteration woks as expected and generated correct code.

Playground Link:

Cannot provide a playground link since --downlevelIteration cannot be enabled in the playground (see #18209)

@NN---
Copy link

NN--- commented Feb 25, 2019

Use this playground: typescript-play.js.org/?downlevelIteration=true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants