diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 1cff02ffc48..f92f6789d29 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1910,6 +1910,17 @@ namespace ts { // This is so that they can flow through PropertyName transforms unaffected. // Instead, we mark the container as ES6, so that it can properly handle the transform. transformFlags = TransformFlags.ContainsComputedPropertyName; + if (subtreeFlags & TransformFlags.ContainsLexicalThis) { + // A computed method name like `[this.getName()](x: string) { ... }` needs to + // distinguish itself from the normal case of a method body containing `this`: + // `this` inside a method doesn't need to be rewritten (the method provides `this`), + // whereas `this` inside a computed name *might* need to be rewritten if the class/object + // is inside an arrow function: + // `_this = this; () => class K { [_this.getName()]() { ... } }` + // To make this distinction, use ContainsLexicalThisInComputedPropertyName + // instead of ContainsLexicalThis for computed property names + transformFlags |= TransformFlags.ContainsLexicalThisInComputedPropertyName; + } break; case SyntaxKind.SpreadElementExpression: @@ -1945,6 +1956,11 @@ namespace ts { // is an ES6 node. transformFlags = TransformFlags.AssertES6; } + if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) { + // A computed property name containing `this` might need to be rewritten, + // so propagate the ContainsLexicalThis flag upward. + transformFlags |= TransformFlags.ContainsLexicalThis; + } break; case SyntaxKind.CallExpression: @@ -2256,6 +2272,11 @@ namespace ts { || hasModifier(node, ModifierFlags.Export)) { transformFlags |= TransformFlags.AssertTypeScript; } + if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) { + // A computed property name containing `this` might need to be rewritten, + // so propagate the ContainsLexicalThis flag upward. + transformFlags |= TransformFlags.ContainsLexicalThis; + } return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ClassExcludes); } @@ -2272,6 +2293,11 @@ namespace ts { | TransformFlags.ContainsDecorators)) { transformFlags |= TransformFlags.AssertTypeScript; } + if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) { + // A computed property name containing `this` might need to be rewritten, + // so propagate the ContainsLexicalThis flag upward. + transformFlags |= TransformFlags.ContainsLexicalThis; + } return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ClassExcludes); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 627b33f0d34..4c99417950d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2830,11 +2830,12 @@ namespace ts { ContainsPropertyInitializer = 1 << 10, ContainsLexicalThis = 1 << 11, ContainsCapturedLexicalThis = 1 << 12, - ContainsDefaultValueAssignments = 1 << 13, - ContainsParameterPropertyAssignments = 1 << 14, - ContainsSpreadElementExpression = 1 << 15, - ContainsComputedPropertyName = 1 << 16, - ContainsBlockScopedBinding = 1 << 17, + ContainsLexicalThisInComputedPropertyName = 1 << 13, + ContainsDefaultValueAssignments = 1 << 14, + ContainsParameterPropertyAssignments = 1 << 15, + ContainsSpreadElementExpression = 1 << 16, + ContainsComputedPropertyName = 1 << 17, + ContainsBlockScopedBinding = 1 << 18, HasComputedFlags = 1 << 31, // Transform flags have been computed. @@ -2853,10 +2854,10 @@ namespace ts { FunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding, ConstructorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding, MethodOrAccessorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding, - ClassExcludes = ContainsDecorators | ContainsPropertyInitializer | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsParameterPropertyAssignments, + ClassExcludes = ContainsDecorators | ContainsPropertyInitializer | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsParameterPropertyAssignments | ContainsLexicalThisInComputedPropertyName, ModuleExcludes = ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding, TypeExcludes = ~ContainsTypeScript, - ObjectLiteralExcludes = ContainsDecorators | ContainsComputedPropertyName, + ObjectLiteralExcludes = ContainsDecorators | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName, ArrayLiteralOrCallOrNewExcludes = ContainsSpreadElementExpression, } diff --git a/tests/baselines/reference/computedPropertyNames29_ES5.js b/tests/baselines/reference/computedPropertyNames29_ES5.js index af6f93c8ad9..966081ae035 100644 --- a/tests/baselines/reference/computedPropertyNames29_ES5.js +++ b/tests/baselines/reference/computedPropertyNames29_ES5.js @@ -18,7 +18,8 @@ var C = (function () { var _this = this; (function () { var obj = (_a = {}, - _a[_this.bar()] = function () { }, + _a[_this.bar()] = function () { } // needs capture + , _a); var _a; }); diff --git a/tests/baselines/reference/computedPropertyNames31_ES5.js b/tests/baselines/reference/computedPropertyNames31_ES5.js index 86fb6655a27..2e38e2a131f 100644 --- a/tests/baselines/reference/computedPropertyNames31_ES5.js +++ b/tests/baselines/reference/computedPropertyNames31_ES5.js @@ -38,7 +38,8 @@ var C = (function (_super) { var _this = this; (function () { var obj = (_a = {}, - _a[_super.prototype.bar.call(_this)] = function () { }, + _a[_super.prototype.bar.call(_this)] = function () { } // needs capture + , _a); var _a; });