diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 51918f70cc6..5956facf319 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3099,8 +3099,7 @@ namespace ts { // If the this node contains a SpreadExpression, or is a super call, then it is an ES6 // node. transformFlags |= TransformFlags.AssertES2015; - // super property or element accesses could be inside lambdas, etc, and need a captured `this`, - // while super keyword for super calls (indicated by TransformFlags.Super) does not (since it can only be top-level in a constructor) + if (expression.transformFlags & TransformFlags.ContainsSuper) { transformFlags |= TransformFlags.ContainsLexicalThis; } @@ -3108,12 +3107,6 @@ namespace ts { if (expression.kind === SyntaxKind.ImportKeyword) { transformFlags |= TransformFlags.ContainsDynamicImport; - - // A dynamic 'import()' call that contains a lexical 'this' will - // require a captured 'this' when emitting down-level. - if (subtreeFlags & TransformFlags.ContainsLexicalThis) { - transformFlags |= TransformFlags.ContainsCapturedLexicalThis; - } } node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; @@ -3236,12 +3229,6 @@ namespace ts { || node.typeParameters) { 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; - } } node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; @@ -3259,12 +3246,6 @@ namespace ts { 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; - } - node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; return transformFlags & ~TransformFlags.ClassExcludes; } @@ -3369,7 +3350,7 @@ namespace ts { } node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; - return transformFlags & ~TransformFlags.MethodOrAccessorExcludes; + return propagatePropertyNameFlags(node.name, transformFlags & ~TransformFlags.MethodOrAccessorExcludes); } function computeAccessor(node: AccessorDeclaration, subtreeFlags: TransformFlags) { @@ -3391,7 +3372,7 @@ namespace ts { } node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; - return transformFlags & ~TransformFlags.MethodOrAccessorExcludes; + return propagatePropertyNameFlags(node.name, transformFlags & ~TransformFlags.MethodOrAccessorExcludes); } function computePropertyDeclaration(node: PropertyDeclaration, subtreeFlags: TransformFlags) { @@ -3405,7 +3386,7 @@ namespace ts { } node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; - return transformFlags & ~TransformFlags.NodeExcludes; + return propagatePropertyNameFlags(node.name, transformFlags & ~TransformFlags.PropertyExcludes); } function computeFunctionDeclaration(node: FunctionDeclaration, subtreeFlags: TransformFlags) { @@ -3439,13 +3420,6 @@ namespace ts { transformFlags |= TransformFlags.AssertES2018; } - // If a FunctionDeclaration's subtree has marked the container as needing to capture the - // lexical this, or the function contains parameters with initializers, then this node is - // ES6 syntax. - if (subtreeFlags & TransformFlags.ContainsCapturedLexicalThis) { - transformFlags |= TransformFlags.AssertES2015; - } - // If a FunctionDeclaration is generator function and is the body of a // transformed async function, then this node can be transformed to a // down-level generator. @@ -3481,14 +3455,6 @@ namespace ts { transformFlags |= TransformFlags.AssertES2018; } - - // If a FunctionExpression's subtree has marked the container as needing to capture the - // lexical this, or the function contains parameters with initializers, then this node is - // ES6 syntax. - if (subtreeFlags & TransformFlags.ContainsCapturedLexicalThis) { - transformFlags |= TransformFlags.AssertES2015; - } - // If a FunctionExpression is generator function and is the body of a // transformed async function, then this node can be transformed to a // down-level generator. @@ -3522,11 +3488,6 @@ namespace ts { transformFlags |= TransformFlags.AssertES2018; } - // If an ArrowFunction contains a lexical this, its container must capture the lexical this. - if (subtreeFlags & TransformFlags.ContainsLexicalThis) { - transformFlags |= TransformFlags.ContainsCapturedLexicalThis; - } - node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; return transformFlags & ~TransformFlags.ArrowFunctionExcludes; } @@ -3810,17 +3771,6 @@ 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.SpreadElement: @@ -3839,7 +3789,6 @@ namespace ts { case SyntaxKind.ThisKeyword: // Mark this node and its ancestors as containing a lexical `this` keyword. - transformFlags |= TransformFlags.AssertES2015; transformFlags |= TransformFlags.ContainsLexicalThis; break; @@ -3876,12 +3825,6 @@ namespace ts { transformFlags |= TransformFlags.AssertES2015; } - if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) { - // A computed property name containing `this` might need to be rewritten, - // so propagate the ContainsLexicalThis flag upward. - transformFlags |= TransformFlags.ContainsLexicalThis; - } - if (subtreeFlags & TransformFlags.ContainsObjectRestOrSpread) { // If an ObjectLiteralExpression contains a spread element, then it // is an ES2018 node. @@ -3906,10 +3849,6 @@ namespace ts { break; case SyntaxKind.SourceFile: - if (subtreeFlags & TransformFlags.ContainsCapturedLexicalThis) { - transformFlags |= TransformFlags.AssertES2015; - } - break; case SyntaxKind.ReturnStatement: @@ -3927,6 +3866,10 @@ namespace ts { return transformFlags & ~excludeFlags; } + function propagatePropertyNameFlags(node: PropertyName, transformFlags: TransformFlags) { + return transformFlags | (node.transformFlags & TransformFlags.PropertyNamePropagatingFlags); + } + /** * Gets the transform flags to exclude when unioning the transform flags of a subtree. * diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 65872188827..610e527451d 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -229,8 +229,7 @@ namespace ts { // NewTarget = 1 << 13, // Contains a 'new.target' meta-property - LexicalThis = 1 << 14, // Contains a lexical `this` reference. - CapturedLexicalThis = 1 << 15, // Contains a lexical `this` reference captured by an arrow function. + CapturedLexicalThis = 1 << 14, // Contains a lexical `this` reference captured by an arrow function. // // Subtree masks @@ -239,7 +238,7 @@ namespace ts { SubtreeFactsMask = ~AncestorFactsMask, ArrowFunctionSubtreeExcludes = None, - FunctionSubtreeExcludes = NewTarget | LexicalThis | CapturedLexicalThis, + FunctionSubtreeExcludes = NewTarget | CapturedLexicalThis, } export function transformES2015(context: TransformationContext) { @@ -565,7 +564,6 @@ namespace ts { } function visitThisKeyword(node: Node): Node { - hierarchyFacts |= HierarchyFacts.LexicalThis; if (hierarchyFacts & HierarchyFacts.ArrowFunction) { hierarchyFacts |= HierarchyFacts.CapturedLexicalThis; } @@ -989,7 +987,7 @@ namespace ts { insertCaptureNewTargetIfNeeded(prologue, constructor, /*copyOnWrite*/ false); if (isDerivedClass) { - if (superCallExpression && statementOffset === constructor.body.statements.length && !(hierarchyFacts & HierarchyFacts.LexicalThis)) { + if (superCallExpression && statementOffset === constructor.body.statements.length && !(constructor.body.transformFlags & TransformFlags.ContainsLexicalThis)) { // If the subclass constructor does *not* contain `this` and *ends* with a `super()` call, we will use the // following representation: // @@ -1693,6 +1691,10 @@ namespace ts { * @param node An ArrowFunction node. */ function visitArrowFunction(node: ArrowFunction) { + if (node.transformFlags & TransformFlags.ContainsLexicalThis) { + hierarchyFacts |= HierarchyFacts.CapturedLexicalThis; + } + const savedConvertedLoopState = convertedLoopState; convertedLoopState = undefined; const ancestorFacts = enterSubtree(HierarchyFacts.ArrowFunctionExcludes, HierarchyFacts.ArrowFunctionIncludes); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 042eefabf50..d6aecb3e177 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5055,20 +5055,18 @@ namespace ts { // Markers // - Flags used to indicate that a subtree contains a specific transformation. - ContainsTypeScriptClassSyntax = 1 << 11, // Decorators, Property Initializers, Parameter Property Initializers - ContainsLexicalThis = 1 << 12, - ContainsCapturedLexicalThis = 1 << 13, - ContainsLexicalThisInComputedPropertyName = 1 << 14, - ContainsRestOrSpread = 1 << 15, - ContainsObjectRestOrSpread = 1 << 16, - ContainsComputedPropertyName = 1 << 17, - ContainsBlockScopedBinding = 1 << 18, - ContainsBindingPattern = 1 << 19, - ContainsYield = 1 << 20, - ContainsHoistedDeclarationOrCompletion = 1 << 21, - ContainsDynamicImport = 1 << 22, - Super = 1 << 23, - ContainsSuper = 1 << 24, + ContainsLexicalThis = 1 << 11, + ContainsTypeScriptClassSyntax = 1 << 12, // Decorators, Property Initializers, Parameter Property Initializers + ContainsRestOrSpread = 1 << 13, + ContainsObjectRestOrSpread = 1 << 14, + ContainsComputedPropertyName = 1 << 15, + ContainsBlockScopedBinding = 1 << 16, + ContainsBindingPattern = 1 << 17, + ContainsYield = 1 << 18, + ContainsHoistedDeclarationOrCompletion = 1 << 19, + ContainsDynamicImport = 1 << 20, + Super = 1 << 21, + ContainsSuper = 1 << 22, // Please leave this as 1 << 29. // It is the maximum bit we can set before we outgrow the size of a v8 small integer (SMI) on an x86 system. @@ -5093,20 +5091,25 @@ namespace ts { OuterExpressionExcludes = DestructuringAssignment | Generator | HasComputedFlags, PropertyAccessExcludes = OuterExpressionExcludes | Super, NodeExcludes = PropertyAccessExcludes | ContainsSuper, - ArrowFunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread, - FunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread, - ConstructorExcludes = NodeExcludes | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread, - MethodOrAccessorExcludes = NodeExcludes | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread, - ClassExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName, - ModuleExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion, + ArrowFunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread, + FunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread, + ConstructorExcludes = NodeExcludes | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread, + MethodOrAccessorExcludes = NodeExcludes | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread, + PropertyExcludes = NodeExcludes | ContainsLexicalThis, + ClassExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName, + ModuleExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion, TypeExcludes = ~ContainsTypeScript, - ObjectLiteralExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName | ContainsObjectRestOrSpread, + ObjectLiteralExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName | ContainsObjectRestOrSpread, ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsRestOrSpread, VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern | ContainsObjectRestOrSpread, ParameterExcludes = NodeExcludes, CatchClauseExcludes = NodeExcludes | ContainsObjectRestOrSpread, BindingPatternExcludes = NodeExcludes | ContainsRestOrSpread, + // Propagating flags + // - Bitmasks for flags that should propagate from a child + PropertyNamePropagatingFlags = ContainsLexicalThis, + // Masks // - Additional bitmasks }