From b5a10316851ec7943ab24ee6127178e705657f1c Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 27 Sep 2016 14:41:47 -0700 Subject: [PATCH] Moved code around, fixed indent, reworded comment. --- src/compiler/transformers/es6.ts | 129 +++++++++++++++---------------- 1 file changed, 64 insertions(+), 65 deletions(-) diff --git a/src/compiler/transformers/es6.ts b/src/compiler/transformers/es6.ts index 481857e0536..0495e422fc3 100644 --- a/src/compiler/transformers/es6.ts +++ b/src/compiler/transformers/es6.ts @@ -161,7 +161,7 @@ namespace ts { * Callers should skip the current statement and avoid any returns of '_this'. */ ReplaceWithReturn, -} + } export function transformES6(context: TransformationContext) { const { @@ -902,7 +902,7 @@ namespace ts { /** * We want to try to avoid emitting a return statement in certain cases if a user already returned something. - * It would be pointless and generate dead code, so we'll try to make things a little bit prettier + * It would generate obviously dead code, so we'll try to make things a little bit prettier * by doing a minimal check on whether some common patterns always explicitly return. */ function isSufficientlyCoveredByReturnStatements(statement: Statement): boolean { @@ -910,7 +910,6 @@ namespace ts { if (statement.kind === SyntaxKind.ReturnStatement) { return true; } - // An if-statement with two covered branches is covered. else if (statement.kind === SyntaxKind.IfStatement) { const ifStatement = statement as IfStatement; @@ -973,6 +972,68 @@ namespace ts { return SuperCaptureResult.NoReplacement; } + /** + * Declares a `_this` variable for derived classes and for when arrow functions capture `this`. + * + * @returns The new statement offset into the `statements` array. + */ + function declareOrCaptureOrReturnThisForConstructorIfNeeded(statements: Statement[], ctor: ConstructorDeclaration, hasExtendsClause: boolean, statementOffset: number) { + // If this isn't a derived class, just capture 'this' for arrow functions if necessary. + if (!hasExtendsClause) { + addCaptureThisForNodeIfNeeded(statements, ctor); + return SuperCaptureResult.NoReplacement; + } + + // Most of the time, a 'super' call will be the first real statement in a constructor body. + // In these cases, we'd like to transform these into a *single* statement instead of a declaration + // followed by an assignment statement for '_this'. For instance, if we emitted without an initializer, + // we'd get: + // + // var _this; + // _this = _super.call(...) || this; + // + // instead of + // + // var _this = _super.call(...) || this; + // + // Additionally, if the 'super()' call is the last statement, we should just avoid capturing + // entirely and immediately return the result like so: + // + // return _super.call(...) || this; + // + let firstStatement: Statement; + let superCallExpression: Expression; + + const ctorStatements = ctor.body.statements; + if (statementOffset < ctorStatements.length) { + firstStatement = ctorStatements[statementOffset]; + + if (firstStatement.kind === SyntaxKind.ExpressionStatement && isSuperCallExpression((firstStatement as ExpressionStatement).expression)) { + const superCall = (firstStatement as ExpressionStatement).expression as CallExpression; + superCallExpression = setOriginalNode( + saveStateAndInvoke(superCall, visitImmediateSuperCallInBody), + superCall + ); + } + } + + // Return the result if we have an immediate super() call on the last statement. + if (superCallExpression && statementOffset === ctorStatements.length - 1) { + statements.push(createReturn(superCallExpression)); + return SuperCaptureResult.ReplaceWithReturn; + } + + // Perform the capture. + captureThisForNode(statements, ctor, superCallExpression, firstStatement); + + // If we're actually replacing the original statement, we need to signal this to the caller. + if (superCallExpression) { + return SuperCaptureResult.ReplaceSuperCapture; + } + + return SuperCaptureResult.NoReplacement; + } + /** * Visits a parameter declaration. * @@ -1216,68 +1277,6 @@ namespace ts { statements.push(forStatement); } - /** - * Declares a `_this` variable for derived classes and for when arrow functions capture `this`. - * - * @returns The new statement offset into the `statements` array. - */ - function declareOrCaptureOrReturnThisForConstructorIfNeeded(statements: Statement[], ctor: ConstructorDeclaration, hasExtendsClause: boolean, statementOffset: number) { - // If this isn't a derived class, just capture 'this' for arrow functions if necessary. - if (!hasExtendsClause) { - addCaptureThisForNodeIfNeeded(statements, ctor); - return SuperCaptureResult.NoReplacement; - } - - // Most of the time, a 'super' call will be the first real statement in a constructor body. - // In these cases, we'd like to transform these into a *single* statement instead of a declaration - // followed by an assignment statement for '_this'. For instance, if we emitted without an initializer, - // we'd get: - // - // var _this; - // _this = _super.call(...) || this; - // - // instead of - // - // var _this = _super.call(...) || this; - // - // Additionally, if the 'super()' call is the last statement, we should just avoid capturing - // entirely and immediately return the result like so: - // - // return _super.call(...) || this; - // - let firstStatement: Statement; - let superCallExpression: Expression; - - const ctorStatements = ctor.body.statements; - if (statementOffset < ctorStatements.length) { - firstStatement = ctorStatements[statementOffset]; - - if (firstStatement.kind === SyntaxKind.ExpressionStatement && isSuperCallExpression((firstStatement as ExpressionStatement).expression)) { - const superCall = (firstStatement as ExpressionStatement).expression as CallExpression; - superCallExpression = setOriginalNode( - saveStateAndInvoke(superCall, visitImmediateSuperCallInBody), - superCall - ); - } - } - - // Return the result if we have an immediate super() call on the last statement. - if (superCallExpression && statementOffset === ctorStatements.length - 1) { - statements.push(createReturn(superCallExpression)); - return SuperCaptureResult.ReplaceWithReturn; - } - - // Perform the capture. - captureThisForNode(statements, ctor, superCallExpression, firstStatement); - - // If we're actually replacing the original statement, we need to signal this to the caller. - if (superCallExpression) { - return SuperCaptureResult.ReplaceSuperCapture; - } - - return SuperCaptureResult.NoReplacement; - } - /** * Adds a statement to capture the `this` of a function declaration if it is needed. *