diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 3e05ce8ec98..65872188827 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -345,13 +345,6 @@ namespace ts { } } - function functionBodyVisitor(node: Block): Block { - if (shouldVisitNode(node)) { - return visitBlock(node, /*isFunctionBody*/ true); - } - return node; - } - function callExpressionVisitor(node: Node): VisitResult { if (node.kind === SyntaxKind.SuperKeyword) { return visitSuperKeyword(/*isExpressionOfCall*/ true); @@ -507,7 +500,6 @@ namespace ts { const statements: Statement[] = []; startLexicalEnvironment(); let statementOffset = addStandardPrologue(prologue, node.statements, /*ensureUseStrict*/ false); - insertCaptureThisForNodeIfNeeded(prologue, node); statementOffset = addCustomPrologue(prologue, node.statements, statementOffset, visitor); addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset)); if (taggedTemplateStringDeclarations) { @@ -515,7 +507,8 @@ namespace ts { createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList(taggedTemplateStringDeclarations))); } - insertStatementsAfterStandardPrologue(prologue, endLexicalEnvironment()); + mergeLexicalEnvironment(prologue, endLexicalEnvironment()); + insertCaptureThisForNodeIfNeeded(prologue, node); exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); return updateSourceFileNode( node, @@ -1194,11 +1187,6 @@ namespace ts { || isBindingPattern(node.name); } - function hasDefaultValueOrBindingPatternOrRest(node: ParameterDeclaration) { - return hasDefaultValueOrBindingPattern(node) - || node.dotDotDotToken !== undefined; - } - /** * Adds statements to the body of a function-like node if it contains parameters with * binding patterns or initializers. @@ -1446,12 +1434,13 @@ namespace ts { /** * Adds a statement to capture the `this` of a function declaration if it is needed. + * NOTE: This must be executed *after* the subtree has been visited. * * @param statements The statements for the new function body. * @param node A node. */ function insertCaptureThisForNodeIfNeeded(statements: Statement[], node: Node): boolean { - if (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) { + if (hierarchyFacts & HierarchyFacts.CapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) { insertCaptureThisForNode(statements, node, createThis()); return true; } @@ -1731,10 +1720,6 @@ namespace ts { return func; } - function containsCapturedLexicalThis(node: Node) { - return (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis) !== 0; - } - /** * Visits a FunctionExpression node. * @@ -1748,11 +1733,7 @@ namespace ts { convertedLoopState = undefined; const parameters = visitParameterList(node.parameters, visitor, context); - const shouldTransform = forEachChild(node, containsCapturedLexicalThis) - || some(node.parameters, hasDefaultValueOrBindingPatternOrRest); - const body = shouldTransform - ? transformFunctionBody(node) - : visitFunctionBodyDownLevel(node); + const body = transformFunctionBody(node); const name = hierarchyFacts & HierarchyFacts.NewTarget ? getLocalName(node) : node.name; @@ -1781,11 +1762,7 @@ namespace ts { convertedLoopState = undefined; const ancestorFacts = enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes); const parameters = visitParameterList(node.parameters, visitor, context); - const shouldTransform = forEachChild(node, containsCapturedLexicalThis) - || some(node.parameters, hasDefaultValueOrBindingPatternOrRest); - const body = shouldTransform - ? transformFunctionBody(node) - : visitFunctionBodyDownLevel(node); + const body = transformFunctionBody(node); const name = hierarchyFacts & HierarchyFacts.NewTarget ? getLocalName(node) : node.name; @@ -1921,7 +1898,13 @@ namespace ts { multiLine = true; } - const block = createBlock(setTextRange(createNodeArray(concatenate(prologue, statements)), statementsLocation), multiLine); + statements.unshift(...prologue); + if (isBlock(body) && arrayIsEqualTo(statements, body.statements)) { + // no changes were made, preserve the tree + return body; + } + + const block = createBlock(setTextRange(createNodeArray(statements), statementsLocation), multiLine); setTextRange(block, node.body); if (!multiLine && singleLine) { setEmitFlags(block, EmitFlags.SingleLine); @@ -1935,19 +1918,6 @@ namespace ts { return block; } - function visitFunctionBodyDownLevel(node: FunctionDeclaration | FunctionExpression | AccessorDeclaration) { - const updated = visitFunctionBody(node.body, functionBodyVisitor, context)!; - return updateBlock( - updated, - setTextRange( - createNodeArray( - insertCaptureNewTargetIfNeeded(updated.statements as MutableNodeArray, node, /*copyOnWrite*/ true) - ), - /*location*/ updated.statements - ) - ); - } - function visitBlock(node: Block, isFunctionBody: boolean): Block { if (isFunctionBody) { // A function body is not a block scope. @@ -3501,9 +3471,7 @@ namespace ts { const ancestorFacts = enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes); let updated: AccessorDeclaration; const parameters = visitParameterList(node.parameters, visitor, context); - const body = node.transformFlags & (TransformFlags.ContainsCapturedLexicalThis | TransformFlags.ContainsES2015) - ? transformFunctionBody(node) - : visitFunctionBodyDownLevel(node); + const body = transformFunctionBody(node); if (node.kind === SyntaxKind.GetAccessor) { updated = updateGetAccessor(node, node.decorators, node.modifiers, node.name, parameters, node.type, body); } diff --git a/tests/baselines/reference/decoratorOnClassMethod11.js b/tests/baselines/reference/decoratorOnClassMethod11.js index e29c4076c91..2600681c647 100644 --- a/tests/baselines/reference/decoratorOnClassMethod11.js +++ b/tests/baselines/reference/decoratorOnClassMethod11.js @@ -17,7 +17,6 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, }; var M; (function (M) { - var _this = this; var C = /** @class */ (function () { function C() { } diff --git a/tests/baselines/reference/dynamicImportWithNestedThis_es5.js b/tests/baselines/reference/dynamicImportWithNestedThis_es5.js index 39fa9fea4a7..81cbcc78e4e 100644 --- a/tests/baselines/reference/dynamicImportWithNestedThis_es5.js +++ b/tests/baselines/reference/dynamicImportWithNestedThis_es5.js @@ -30,7 +30,6 @@ c.dynamic(); } C.prototype.dynamic = function () { var _a; - var _this = this; return _a = this._path, __syncRequire ? Promise.resolve().then(function () { return require(_a); }) : new Promise(function (resolve_1, reject_1) { require([_a], resolve_1, reject_1); }); }; return C; diff --git a/tests/baselines/reference/newTarget.es5.js b/tests/baselines/reference/newTarget.es5.js index 5a27ed7efc7..7fa733880b4 100644 --- a/tests/baselines/reference/newTarget.es5.js +++ b/tests/baselines/reference/newTarget.es5.js @@ -49,11 +49,17 @@ var __extends = (this && this.__extends) || (function () { var A = /** @class */ (function () { function A() { var _newTarget = this.constructor; - this.d = function _a() { var _newTarget = this && this instanceof _a ? this.constructor : void 0; return _newTarget; }; + this.d = function _a() { + var _newTarget = this && this instanceof _a ? this.constructor : void 0; + return _newTarget; + }; var a = _newTarget; var b = function () { return _newTarget; }; } - A.c = function _a() { var _newTarget = this && this instanceof _a ? this.constructor : void 0; return _newTarget; }; + A.c = function _a() { + var _newTarget = this && this instanceof _a ? this.constructor : void 0; + return _newTarget; + }; return A; }()); var B = /** @class */ (function (_super) { @@ -78,5 +84,8 @@ var f2 = function _b() { var j = function () { return _newTarget; }; }; var O = { - k: function k() { var _newTarget = this && this instanceof k ? this.constructor : void 0; return _newTarget; } + k: function k() { + var _newTarget = this && this instanceof k ? this.constructor : void 0; + return _newTarget; + } }; diff --git a/tests/baselines/reference/thisInConstructorParameter2.js b/tests/baselines/reference/thisInConstructorParameter2.js index 584418f419d..df2f22b8ae7 100644 --- a/tests/baselines/reference/thisInConstructorParameter2.js +++ b/tests/baselines/reference/thisInConstructorParameter2.js @@ -12,7 +12,6 @@ class P { } //// [thisInConstructorParameter2.js] -var _this = this; var P = /** @class */ (function () { function P(z, zz, zzz) { var _this = this; diff --git a/tests/baselines/reference/thisInInvalidContexts.js b/tests/baselines/reference/thisInInvalidContexts.js index 9ce5071c903..71c0a408c45 100644 --- a/tests/baselines/reference/thisInInvalidContexts.js +++ b/tests/baselines/reference/thisInInvalidContexts.js @@ -62,7 +62,6 @@ var __extends = (this && this.__extends) || (function () { d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); -var _this = this; //'this' in static member initializer var ErrClass1 = /** @class */ (function () { function ErrClass1() { diff --git a/tests/baselines/reference/thisInInvalidContextsExternalModule.js b/tests/baselines/reference/thisInInvalidContextsExternalModule.js index 92f6afc8c29..e295c49074b 100644 --- a/tests/baselines/reference/thisInInvalidContextsExternalModule.js +++ b/tests/baselines/reference/thisInInvalidContextsExternalModule.js @@ -63,7 +63,6 @@ var __extends = (this && this.__extends) || (function () { d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); -var _this = this; //'this' in static member initializer var ErrClass1 = /** @class */ (function () { function ErrClass1() { diff --git a/tests/baselines/reference/thisInOuterClassBody.js b/tests/baselines/reference/thisInOuterClassBody.js index d5bf689b49a..2b4e3a1aabd 100644 --- a/tests/baselines/reference/thisInOuterClassBody.js +++ b/tests/baselines/reference/thisInOuterClassBody.js @@ -21,7 +21,6 @@ class Foo { } //// [thisInOuterClassBody.js] -var _this = this; var Foo = /** @class */ (function () { function Foo() { this.x = this; diff --git a/tests/baselines/reference/typeOfThisInStaticMembers2.js b/tests/baselines/reference/typeOfThisInStaticMembers2.js index 1cfec3a3fa1..72243cdd3e6 100644 --- a/tests/baselines/reference/typeOfThisInStaticMembers2.js +++ b/tests/baselines/reference/typeOfThisInStaticMembers2.js @@ -8,7 +8,6 @@ class C2 { } //// [typeOfThisInStaticMembers2.js] -var _this = this; var C = /** @class */ (function () { function C() { }