diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9ec88e0be3e..19ddbcdac04 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17892,6 +17892,9 @@ namespace ts { } if (requestedExternalEmitHelpers & NodeFlags.HasAsyncFunctions) { verifyHelperSymbol(exports, "__awaiter", SymbolFlags.Value); + if (languageVersion < ScriptTarget.ES6) { + verifyHelperSymbol(exports, "__generator", SymbolFlags.Value); + } } } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 99b0535da47..09c785a24e3 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -73,51 +73,40 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge const generatorHelper = ` var __generator = (this && this.__generator) || function (body) { - var _ = { label: 0, sent: function() { if (sent[0] === 1 /*throw*/) throw sent[1]; return sent[1]; }, trys: [], stack: [] }, sent; + var _ = { label: 0, sent: function() { if (sent[0] === 1) throw sent[1]; return sent[1]; }, trys: [], stack: [] }, sent, f; function step(op) { - if (_.flag) throw new TypeError("Generator is already executing."); - while (true) { + if (f) throw new TypeError("Generator is already executing."); + while (1) { if (_.done) switch (op[0]) { - case 0 /*next*/: return { value: void 0, done: true }; - case 1 /*throw*/: case 6 /*catch*/: throw op[1]; - case 2 /*return*/: return { value: op[1], done: true }; + case 0: return { value: void 0, done: true }; + case 1: case 6: throw op[1]; + case 2: return { value: op[1], done: true }; } try { - switch (_.flag = true, op[0]) { - case 0 /*next*/: case 1 /*throw*/: sent = op; break; - case 4 /*yield*/: return _.label++, { value: op[1], done: false }; - case 7 /*endfinally*/: op = _.stack.pop(), _.trys.pop(); continue; + switch (f = 1, op[0]) { + case 0: case 1: sent = op; break; + case 4: return _.label++, { value: op[1], done: false }; + case 7: op = _.stack.pop(), _.trys.pop(); continue; default: var r = _.trys.length > 0 && _.trys[_.trys.length - 1]; - if (!r && (op[0] === 1 /*throw*/ || op[0] === 6 /*catch*/ || op[0] === 2 /*return*/)) { - _.done = true; - continue; - } - if (op[0] === 3 /*break*/ && (!r || (op[1] > r[0] && op[1] < r[3]))) { - _.label = op[1]; - } - else if (op[0] === 6 /*catch*/ && r && _.label < r[1]) { - _.label = r[1], sent = op; - } - else if (r && _.label < r[2]) { - _.label = r[2], _.stack.push(op); - } - else { - if (r[2]) _.stack.pop(); - _.trys.pop(); - continue; - } + if (!r && (op[0] === 6 || op[0] === 2)) { _.done = 1; continue; } + if (op[0] === 3 && (!r || (op[1] > r[0] && op[1] < r[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < r[1]) { _.label = r[1], sent = op; break; } + if (r && _.label < r[2]) { _.label = r[2], _.stack.push(op); break; } + if (r[2]) { _.stack.pop(); } + _.trys.pop(); + continue; } op = body(_); } - catch (e) { op = [6 /*catch*/, e]; } - finally { _.flag = false, sent = void 0; } + catch (e) { op = [6, e]; } + finally { f = 0, sent = void 0; } } } return { - next: function (v) { return step([0 /*next*/, v]); }, - "throw": function (v) { return step([1 /*throw*/, v]); }, - "return": function (v) { return step([2 /*return*/, v]); } + next: function (v) { return step([0, v]); }, + "throw": function (v) { return step([1, v]); }, + "return": function (v) { return step([2, v]); } }; };`; diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index 133ed01f091..e11804bd467 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -137,11 +137,7 @@ namespace ts { Endfinally // Marks the end of a `finally` block } - type OperationArguments = [Label] - | [Label, Expression] - | [Statement] - | [Expression] - | [Expression, Expression]; + type OperationArguments = [Label] | [Label, Expression] | [Statement] | [Expression] | [Expression, Expression]; // whether a generated code block is opening or closing at the current operation for a FunctionBuilder const enum BlockAction { @@ -245,6 +241,7 @@ namespace ts { const previousOnSubstituteNode = context.onSubstituteNode; context.onSubstituteNode = onSubstituteNode; + let currentSourceFile: SourceFile; let renamedCatchVariables: Map; let renamedCatchVariableDeclarations: Map; @@ -297,7 +294,9 @@ namespace ts { function transformSourceFile(node: SourceFile) { if (node.transformFlags & TransformFlags.ContainsGenerator) { - return visitEachChild(node, visitor, context); + currentSourceFile = node; + node = visitEachChild(node, visitor, context); + currentSourceFile = undefined; } return node; @@ -2550,7 +2549,7 @@ namespace ts { const buildResult = buildStatements(); return createCall( - createIdentifier("__generator"), + createHelperName(currentSourceFile.externalHelpersModuleName, "__generator"), /*typeArguments*/ undefined, [setNodeEmitFlags( createFunctionExpression( diff --git a/tests/baselines/reference/disallowAsyncModifierInES5.errors.txt b/tests/baselines/reference/disallowAsyncModifierInES5.errors.txt deleted file mode 100644 index eb3cc8218d1..00000000000 --- a/tests/baselines/reference/disallowAsyncModifierInES5.errors.txt +++ /dev/null @@ -1,27 +0,0 @@ -error TS2318: Cannot find global type 'Promise'. -tests/cases/compiler/disallowAsyncModifierInES5.ts(2,1): error TS1311: Async functions are only available when targeting ECMAScript 2015 or higher. -tests/cases/compiler/disallowAsyncModifierInES5.ts(2,16): error TS1057: An async function or method must have a valid awaitable return type. -tests/cases/compiler/disallowAsyncModifierInES5.ts(3,11): error TS1057: An async function or method must have a valid awaitable return type. -tests/cases/compiler/disallowAsyncModifierInES5.ts(3,11): error TS1311: Async functions are only available when targeting ECMAScript 2015 or higher. -tests/cases/compiler/disallowAsyncModifierInES5.ts(4,11): error TS1311: Async functions are only available when targeting ECMAScript 2015 or higher. -tests/cases/compiler/disallowAsyncModifierInES5.ts(4,11): error TS1057: An async function or method must have a valid awaitable return type. - - -!!! error TS2318: Cannot find global type 'Promise'. -==== tests/cases/compiler/disallowAsyncModifierInES5.ts (6 errors) ==== - - async function foo() { return 42; } // ERROR: Async functions are only available in ES6+ - ~~~~~ -!!! error TS1311: Async functions are only available when targeting ECMAScript 2015 or higher. - ~~~ -!!! error TS1057: An async function or method must have a valid awaitable return type. - let bar = async function () { return 42; } // OK, but should be an error - ~~~~~ -!!! error TS1057: An async function or method must have a valid awaitable return type. - ~~~~~ -!!! error TS1311: Async functions are only available when targeting ECMAScript 2015 or higher. - let baz = async () => 42; // OK, but should be an error - ~~~~~ -!!! error TS1311: Async functions are only available when targeting ECMAScript 2015 or higher. - ~~~~~~~~~~~~~~ -!!! error TS1057: An async function or method must have a valid awaitable return type. \ No newline at end of file diff --git a/tests/baselines/reference/disallowAsyncModifierInES5.js b/tests/baselines/reference/disallowAsyncModifierInES5.js deleted file mode 100644 index e0997f13110..00000000000 --- a/tests/baselines/reference/disallowAsyncModifierInES5.js +++ /dev/null @@ -1,23 +0,0 @@ -//// [disallowAsyncModifierInES5.ts] - -async function foo() { return 42; } // ERROR: Async functions are only available in ES6+ -let bar = async function () { return 42; } // OK, but should be an error -let baz = async () => 42; // OK, but should be an error - -//// [disallowAsyncModifierInES5.js] -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments)).next()); - }); -}; -var _this = this; -function foo() { - return __awaiter(this, void 0, void 0, function* () { return 42; }); -} // ERROR: Async functions are only available in ES6+ -var bar = function () { - return __awaiter(this, void 0, void 0, function* () { return 42; }); -}; // OK, but should be an error -var baz = function () { return __awaiter(_this, void 0, void 0, function* () { return 42; }); }; // OK, but should be an error diff --git a/tests/baselines/reference/es5-asyncFunction.js b/tests/baselines/reference/es5-asyncFunction.js index 28197f55bae..57c9a7c05f6 100644 --- a/tests/baselines/reference/es5-asyncFunction.js +++ b/tests/baselines/reference/es5-asyncFunction.js @@ -18,51 +18,40 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; var __generator = (this && this.__generator) || function (body) { - var _ = { label: 0, sent: function() { if (sent[0] === 1 /*throw*/) throw sent[1]; return sent[1]; }, trys: [], stack: [] }, sent; + var _ = { label: 0, sent: function() { if (sent[0] === 1) throw sent[1]; return sent[1]; }, trys: [], stack: [] }, sent, f; function step(op) { - if (_.flag) throw new TypeError("Generator is already executing."); - while (true) { + if (f) throw new TypeError("Generator is already executing."); + while (1) { if (_.done) switch (op[0]) { - case 0 /*next*/: return { value: void 0, done: true }; - case 1 /*throw*/: case 6 /*catch*/: throw op[1]; - case 2 /*return*/: return { value: op[1], done: true }; + case 0: return { value: void 0, done: true }; + case 1: case 6: throw op[1]; + case 2: return { value: op[1], done: true }; } try { - switch (_.flag = true, op[0]) { - case 0 /*next*/: case 1 /*throw*/: sent = op; break; - case 4 /*yield*/: return _.label++, { value: op[1], done: false }; - case 7 /*endfinally*/: op = _.stack.pop(), _.trys.pop(); continue; + switch (f = 1, op[0]) { + case 0: case 1: sent = op; break; + case 4: return _.label++, { value: op[1], done: false }; + case 7: op = _.stack.pop(), _.trys.pop(); continue; default: var r = _.trys.length > 0 && _.trys[_.trys.length - 1]; - if (!r && (op[0] === 1 /*throw*/ || op[0] === 6 /*catch*/ || op[0] === 2 /*return*/)) { - _.done = true; - continue; - } - if (op[0] === 3 /*break*/ && (!r || (op[1] > r[0] && op[1] < r[3]))) { - _.label = op[1]; - } - else if (op[0] === 6 /*catch*/ && r && _.label < r[1]) { - _.label = r[1], sent = op; - } - else if (r && _.label < r[2]) { - _.label = r[2], _.stack.push(op); - } - else { - if (r[2]) _.stack.pop(); - _.trys.pop(); - continue; - } + if (!r && (op[0] === 6 || op[0] === 2)) { _.done = 1; continue; } + if (op[0] === 3 && (!r || (op[1] > r[0] && op[1] < r[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < r[1]) { _.label = r[1], sent = op; break; } + if (r && _.label < r[2]) { _.label = r[2], _.stack.push(op); break; } + if (r[2]) { _.stack.pop(); } + _.trys.pop(); + continue; } op = body(_); } - catch (e) { op = [6 /*catch*/, e]; } - finally { _.flag = false, sent = void 0; } + catch (e) { op = [6, e]; } + finally { f = 0, sent = void 0; } } } return { - next: function (v) { return step([0 /*next*/, v]); }, - "throw": function (v) { return step([1 /*throw*/, v]); }, - "return": function (v) { return step([2 /*return*/, v]); } + next: function (v) { return step([0, v]); }, + "throw": function (v) { return step([1, v]); }, + "return": function (v) { return step([2, v]); } }; }; function empty() { diff --git a/tests/baselines/reference/es5-importHelpersAsyncFunctions.js b/tests/baselines/reference/es5-importHelpersAsyncFunctions.js new file mode 100644 index 00000000000..b90e2248c2c --- /dev/null +++ b/tests/baselines/reference/es5-importHelpersAsyncFunctions.js @@ -0,0 +1,83 @@ +//// [tests/cases/compiler/es5-importHelpersAsyncFunctions.ts] //// + +//// [external.ts] +export async function foo() { +} + +//// [script.ts] +async function foo() { +} + +//// [tslib.d.ts] +export declare function __extends(d: Function, b: Function): void; +export declare function __assign(t: any, ...sources: any[]): any; +export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; +export declare function __param(paramIndex: number, decorator: Function): Function; +export declare function __metadata(metadataKey: any, metadataValue: any): Function; +export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any; +export declare function __generator(body: Function): any; + +//// [external.js] +"use strict"; +var tslib_1 = require("tslib"); +function foo() { + return tslib_1.__awaiter(this, void 0, void 0, function () { + return tslib_1.__generator(function (_a) { + return [2 /*return*/]; + }); + }); +} +exports.foo = foo; +//// [script.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments)).next()); + }); +}; +var __generator = (this && this.__generator) || function (body) { + var _ = { label: 0, sent: function() { if (sent[0] === 1) throw sent[1]; return sent[1]; }, trys: [], stack: [] }, sent, f; + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (1) { + if (_.done) switch (op[0]) { + case 0: return { value: void 0, done: true }; + case 1: case 6: throw op[1]; + case 2: return { value: op[1], done: true }; + } + try { + switch (f = 1, op[0]) { + case 0: case 1: sent = op; break; + case 4: return _.label++, { value: op[1], done: false }; + case 7: op = _.stack.pop(), _.trys.pop(); continue; + default: + var r = _.trys.length > 0 && _.trys[_.trys.length - 1]; + if (!r && (op[0] === 6 || op[0] === 2)) { _.done = 1; continue; } + if (op[0] === 3 && (!r || (op[1] > r[0] && op[1] < r[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < r[1]) { _.label = r[1], sent = op; break; } + if (r && _.label < r[2]) { _.label = r[2], _.stack.push(op); break; } + if (r[2]) { _.stack.pop(); } + _.trys.pop(); + continue; + } + op = body(_); + } + catch (e) { op = [6, e]; } + finally { f = 0, sent = void 0; } + } + } + return { + next: function (v) { return step([0, v]); }, + "throw": function (v) { return step([1, v]); }, + "return": function (v) { return step([2, v]); } + }; +}; +function foo() { + return __awaiter(this, void 0, void 0, function () { + return __generator(function (_a) { + return [2 /*return*/]; + }); + }); +} diff --git a/tests/baselines/reference/es5-importHelpersAsyncFunctions.symbols b/tests/baselines/reference/es5-importHelpersAsyncFunctions.symbols new file mode 100644 index 00000000000..89660cea722 --- /dev/null +++ b/tests/baselines/reference/es5-importHelpersAsyncFunctions.symbols @@ -0,0 +1,58 @@ +=== tests/cases/compiler/external.ts === +export async function foo() { +>foo : Symbol(foo, Decl(external.ts, 0, 0)) +} + +=== tests/cases/compiler/script.ts === +async function foo() { +>foo : Symbol(foo, Decl(script.ts, 0, 0)) +} + +=== tests/cases/compiler/tslib.d.ts === +export declare function __extends(d: Function, b: Function): void; +>__extends : Symbol(__extends, Decl(tslib.d.ts, --, --)) +>d : Symbol(d, Decl(tslib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(tslib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +export declare function __assign(t: any, ...sources: any[]): any; +>__assign : Symbol(__assign, Decl(tslib.d.ts, --, --)) +>t : Symbol(t, Decl(tslib.d.ts, --, --)) +>sources : Symbol(sources, Decl(tslib.d.ts, --, --)) + +export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; +>__decorate : Symbol(__decorate, Decl(tslib.d.ts, --, --)) +>decorators : Symbol(decorators, Decl(tslib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>target : Symbol(target, Decl(tslib.d.ts, --, --)) +>key : Symbol(key, Decl(tslib.d.ts, --, --)) +>desc : Symbol(desc, Decl(tslib.d.ts, --, --)) + +export declare function __param(paramIndex: number, decorator: Function): Function; +>__param : Symbol(__param, Decl(tslib.d.ts, --, --)) +>paramIndex : Symbol(paramIndex, Decl(tslib.d.ts, --, --)) +>decorator : Symbol(decorator, Decl(tslib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +export declare function __metadata(metadataKey: any, metadataValue: any): Function; +>__metadata : Symbol(__metadata, Decl(tslib.d.ts, --, --)) +>metadataKey : Symbol(metadataKey, Decl(tslib.d.ts, --, --)) +>metadataValue : Symbol(metadataValue, Decl(tslib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any; +>__awaiter : Symbol(__awaiter, Decl(tslib.d.ts, --, --)) +>thisArg : Symbol(thisArg, Decl(tslib.d.ts, --, --)) +>_arguments : Symbol(_arguments, Decl(tslib.d.ts, --, --)) +>P : Symbol(P, Decl(tslib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>generator : Symbol(generator, Decl(tslib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +export declare function __generator(body: Function): any; +>__generator : Symbol(__generator, Decl(tslib.d.ts, --, --)) +>body : Symbol(body, Decl(tslib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + diff --git a/tests/baselines/reference/es5-importHelpersAsyncFunctions.types b/tests/baselines/reference/es5-importHelpersAsyncFunctions.types new file mode 100644 index 00000000000..9ceeee92bc8 --- /dev/null +++ b/tests/baselines/reference/es5-importHelpersAsyncFunctions.types @@ -0,0 +1,58 @@ +=== tests/cases/compiler/external.ts === +export async function foo() { +>foo : () => Promise +} + +=== tests/cases/compiler/script.ts === +async function foo() { +>foo : () => Promise +} + +=== tests/cases/compiler/tslib.d.ts === +export declare function __extends(d: Function, b: Function): void; +>__extends : (d: Function, b: Function) => void +>d : Function +>Function : Function +>b : Function +>Function : Function + +export declare function __assign(t: any, ...sources: any[]): any; +>__assign : (t: any, ...sources: any[]) => any +>t : any +>sources : any[] + +export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; +>__decorate : (decorators: Function[], target: any, key?: string | symbol, desc?: any) => any +>decorators : Function[] +>Function : Function +>target : any +>key : string | symbol +>desc : any + +export declare function __param(paramIndex: number, decorator: Function): Function; +>__param : (paramIndex: number, decorator: Function) => Function +>paramIndex : number +>decorator : Function +>Function : Function +>Function : Function + +export declare function __metadata(metadataKey: any, metadataValue: any): Function; +>__metadata : (metadataKey: any, metadataValue: any) => Function +>metadataKey : any +>metadataValue : any +>Function : Function + +export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any; +>__awaiter : (thisArg: any, _arguments: any, P: Function, generator: Function) => any +>thisArg : any +>_arguments : any +>P : Function +>Function : Function +>generator : Function +>Function : Function + +export declare function __generator(body: Function): any; +>__generator : (body: Function) => any +>body : Function +>Function : Function + diff --git a/tests/cases/compiler/disallowAsyncModifierInES5.ts b/tests/cases/compiler/disallowAsyncModifierInES5.ts deleted file mode 100644 index 5417e678dce..00000000000 --- a/tests/cases/compiler/disallowAsyncModifierInES5.ts +++ /dev/null @@ -1,5 +0,0 @@ -// @target: es5 - -async function foo() { return 42; } // ERROR: Async functions are only available in ES6+ -let bar = async function () { return 42; } // OK, but should be an error -let baz = async () => 42; // OK, but should be an error \ No newline at end of file diff --git a/tests/cases/compiler/es5-importHelpersAsyncFunctions.ts b/tests/cases/compiler/es5-importHelpersAsyncFunctions.ts new file mode 100644 index 00000000000..87acc67a59b --- /dev/null +++ b/tests/cases/compiler/es5-importHelpersAsyncFunctions.ts @@ -0,0 +1,21 @@ +// @lib: es5,es2015.promise +// @importHelpers: true +// @target: es5 +// @module: commonjs +// @moduleResolution: classic +// @filename: external.ts +export async function foo() { +} + +// @filename: script.ts +async function foo() { +} + +// @filename: tslib.d.ts +export declare function __extends(d: Function, b: Function): void; +export declare function __assign(t: any, ...sources: any[]): any; +export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; +export declare function __param(paramIndex: number, decorator: Function): Function; +export declare function __metadata(metadataKey: any, metadataValue: any): Function; +export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any; +export declare function __generator(body: Function): any; \ No newline at end of file