-
Notifications
You must be signed in to change notification settings - Fork 13.1k
Description
TypeScript Version: 4.0.2
Search Terms: async argument throw emit lower incorrect behavior
Code
(async() => {
async function f1(x, y = z) {}
async function f2({[z]: x}) {}
for (let f of [f1, f2]) {
let p = f({}) // This should not throw an error
try {
await p
} catch (e) {
continue // This error is expected
}
throw new Error('Expected an error')
}
})()Expected behavior:
The code should run without crashing, both when compiled to ESNext and when compiled to ES2015.
Actual behavior:
The code crashes with ReferenceError: z is not defined when compiled to ES2015. This is because the generated code moves the evaluation of default arguments from inside the promise context to outside of the promise context during lowering:
function f1(x, y = z) {
return __awaiter(this, void 0, void 0, function* () { });
}
function f2({ [z]: x }) {
return __awaiter(this, void 0, void 0, function* () { });
}There are many ways to fix this, but an example correct compilation might look something like this:
function f1(_0) {
return __awaiter(this, arguments, void 0, function* (x, y = z) { });
}
function f2(_0) {
return __awaiter(this, arguments, void 0, function* ({ [z]: x }) { });
}The _0 variables are to ensure f1.length and f2.length don't change.
I discovered this correctness issue because I replicated TypeScript's approach to async function lowering into esbuild but it turned out to have this correctness issue.
Playground Link: link
Related Issues: