Skip to content

Downlevel async functions issue with captured block scope variables #10889

Closed
@rbuckton

Description

@rbuckton

The downlevel emit for async functions is missing support for handling captured block-scope variables.

Example:

async function fn() {
for (let i = 0; i < 1; i++) return await () => i;
}

Actual:

function fn() {
    return __awaiter(this, void 0, void 0, function () {
        var _loop_1, i;
        return __generator(this, function (_a) {
            _loop_1 = function (i) {
                return { value: yield (function () { return i; }) };
            };
            for (i = 0; i < 1; i++) {
                var state_1 = _loop_1(i);
                if (typeof state_1 === "object")
                    return state_1.value;
            }
            return [2 /*return*/];
        });
    });
}

The yield in _loop_1 is incorrect, since _loop_1 is not a generator.

The simplest solution is to turn the _loop_1 function into a generator, and add the yield* support from #10106, allowing us to delegate the yield expression inside of _loop_1 to __awaiter, but preserve the same return semantics used by the loop body transform.

The resulting emit should be something more like this:

function fn() {
    return __awaiter(this, void 0, void 0, function () {
        var _loop_1, i, state_1;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    _loop_1 = function (i) {
                        var _a;
                        return __generator(this, function (_b) {
                            switch (_b.label) {
                                case 0:
                                    _a = {};
                                    return [4 /*yield*/, (function () { return i; })];
                                case 1: return [2 /*return*/, (_a.value = _b.sent(), _a)];
                            }
                        });
                    };
                    i = 0;
                    _a.label = 1;
                case 1:
                    if (!(i < 1))
                        return [3 /*break*/, 4];
                    return [5 /*yield**/, _loop_1(i)];
                case 2:
                    state_1 = _a.sent();
                    if (typeof state_1 === "object")
                        return [2 /*return*/, state_1.value];
                    _a.label = 3;
                case 3:
                    i++;
                    return [3 /*break*/, 1];
                case 4: return [2 /*return*/];
            }
        });
    });
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptDomain: TransformsRelates to the public transform APIFixedA PR has been merged for this issue

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions