From 7f98d3dbb2ef6a1b21e26e861190188fb02d0fec Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Sat, 24 Sep 2016 16:07:13 -0700 Subject: [PATCH] Fix some issues with module ES6/target ES5 --- src/compiler/transformers/destructuring.ts | 25 +++++++++++-- src/compiler/transformers/es6.ts | 37 ++++++++++++++++--- .../reference/es6modulekindWithES5Target6.js | 6 +-- .../functionsWithModifiersInBlocks1.js | 2 +- .../reference/moduleElementsInWrongContext.js | 2 +- .../moduleElementsInWrongContext2.js | 2 +- .../parserModifierOnStatementInBlock3.js | 2 +- .../parserModifierOnStatementInBlock4.js | 2 +- 8 files changed, 61 insertions(+), 17 deletions(-) diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index c6079ee13786a..a66f5e21d784d 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -126,14 +126,22 @@ namespace ts { context: TransformationContext, node: VariableDeclaration, value?: Expression, - visitor?: (node: Node) => VisitResult) { + visitor?: (node: Node) => VisitResult, + recordTempVariable?: (node: Identifier) => void) { const declarations: VariableDeclaration[] = []; + let pendingAssignments: Expression[]; flattenDestructuring(context, node, value, node, emitAssignment, emitTempVariableAssignment, visitor); return declarations; function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) { + if (pendingAssignments) { + pendingAssignments.push(value); + value = inlineExpressions(pendingAssignments); + pendingAssignments = undefined; + } + const declaration = createVariableDeclaration(name, /*type*/ undefined, value, location); declaration.original = original; @@ -146,8 +154,19 @@ namespace ts { } function emitTempVariableAssignment(value: Expression, location: TextRange) { - const name = createTempVariable(/*recordTempVariable*/ undefined); - emitAssignment(name, value, location, /*original*/ undefined); + const name = createTempVariable(recordTempVariable); + if (recordTempVariable) { + const assignment = createAssignment(name, value, location); + if (pendingAssignments) { + pendingAssignments.push(assignment); + } + else { + pendingAssignments = [assignment]; + } + } + else { + emitAssignment(name, value, location, /*original*/ undefined); + } return name; } } diff --git a/src/compiler/transformers/es6.ts b/src/compiler/transformers/es6.ts index 51a6a088fb717..128692eed853c 100644 --- a/src/compiler/transformers/es6.ts +++ b/src/compiler/transformers/es6.ts @@ -163,6 +163,7 @@ namespace ts { let currentText: string; let currentParent: Node; let currentNode: Node; + let enclosingVariableStatement: VariableStatement; let enclosingBlockScopeContainer: Node; let enclosingBlockScopeContainerParent: Node; let containingNonArrowFunction: FunctionLikeDeclaration | ClassElement; @@ -210,6 +211,7 @@ namespace ts { const savedSuperScopeContainer = superScopeContainer; const savedCurrentParent = currentParent; const savedCurrentNode = currentNode; + const savedEnclosingVariableStatement = enclosingVariableStatement; const savedEnclosingBlockScopeContainer = enclosingBlockScopeContainer; const savedEnclosingBlockScopeContainerParent = enclosingBlockScopeContainerParent; @@ -227,6 +229,7 @@ namespace ts { superScopeContainer = savedSuperScopeContainer; currentParent = savedCurrentParent; currentNode = savedCurrentNode; + enclosingVariableStatement = savedEnclosingVariableStatement; enclosingBlockScopeContainer = savedEnclosingBlockScopeContainer; enclosingBlockScopeContainerParent = savedEnclosingBlockScopeContainerParent; return visited; @@ -320,7 +323,7 @@ namespace ts { return visitFunctionExpression(node); case SyntaxKind.VariableDeclaration: - return visitVariableDeclaration(node, /*offset*/ undefined); + return visitVariableDeclaration(node); case SyntaxKind.Identifier: return visitIdentifier(node); @@ -432,6 +435,25 @@ namespace ts { } break; } + + // keep track of the enclosing variable statement when in the context of + // variable statements, variable declarations, binding elements, and binding + // patterns. + switch (currentParent.kind) { + case SyntaxKind.VariableStatement: + enclosingVariableStatement = currentParent; + break; + + case SyntaxKind.VariableDeclarationList: + case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + break; + + default: + enclosingVariableStatement = undefined; + } } } @@ -1334,7 +1356,7 @@ namespace ts { return setOriginalNode( createFunctionDeclaration( /*decorators*/ undefined, - /*modifiers*/ undefined, + node.modifiers, node.asteriskToken, node.name, /*typeParameters*/ undefined, @@ -1663,13 +1685,13 @@ namespace ts { * * @param node A VariableDeclaration node. */ - function visitVariableDeclarationInLetDeclarationList(node: VariableDeclaration, offset: number) { + function visitVariableDeclarationInLetDeclarationList(node: VariableDeclaration) { // For binding pattern names that lack initializers there is no point to emit // explicit initializer since downlevel codegen for destructuring will fail // in the absence of initializer so all binding elements will say uninitialized const name = node.name; if (isBindingPattern(name)) { - return visitVariableDeclaration(node, offset); + return visitVariableDeclaration(node); } if (!node.initializer && shouldEmitExplicitInitializerForLetDeclaration(node)) { @@ -1686,10 +1708,13 @@ namespace ts { * * @param node A VariableDeclaration node. */ - function visitVariableDeclaration(node: VariableDeclaration, offset: number): VisitResult { + function visitVariableDeclaration(node: VariableDeclaration): VisitResult { // If we are here it is because the name contains a binding pattern. if (isBindingPattern(node.name)) { - return flattenVariableDestructuring(context, node, /*value*/ undefined, visitor); + const recordTempVariablesInLine = !enclosingVariableStatement + || !hasModifier(enclosingVariableStatement, ModifierFlags.Export); + return flattenVariableDestructuring(context, node, /*value*/ undefined, visitor, + recordTempVariablesInLine ? undefined : hoistVariableDeclaration); } return visitEachChild(node, visitor, context); diff --git a/tests/baselines/reference/es6modulekindWithES5Target6.js b/tests/baselines/reference/es6modulekindWithES5Target6.js index 6f8de9db81658..d305c60e54ec6 100644 --- a/tests/baselines/reference/es6modulekindWithES5Target6.js +++ b/tests/baselines/reference/es6modulekindWithES5Target6.js @@ -11,15 +11,15 @@ export default function f3(d = 0) { //// [es6modulekindWithES5Target6.js] -function f1(d) { +export function f1(d) { if (d === void 0) { d = 0; } } -function f2() { +export function f2() { var arg = []; for (var _i = 0; _i < arguments.length; _i++) { arg[_i - 0] = arguments[_i]; } } -function f3(d) { +export default function f3(d) { if (d === void 0) { d = 0; } } diff --git a/tests/baselines/reference/functionsWithModifiersInBlocks1.js b/tests/baselines/reference/functionsWithModifiersInBlocks1.js index 3edd17321cb7d..873411afd2a06 100644 --- a/tests/baselines/reference/functionsWithModifiersInBlocks1.js +++ b/tests/baselines/reference/functionsWithModifiersInBlocks1.js @@ -7,5 +7,5 @@ //// [functionsWithModifiersInBlocks1.js] { - function f() { } + export function f() { } } diff --git a/tests/baselines/reference/moduleElementsInWrongContext.js b/tests/baselines/reference/moduleElementsInWrongContext.js index cd440bd6017a4..b8c7ae25730ad 100644 --- a/tests/baselines/reference/moduleElementsInWrongContext.js +++ b/tests/baselines/reference/moduleElementsInWrongContext.js @@ -45,7 +45,7 @@ return C; }()); export default C; - function bee() { } + export function bee() { } import I2 = require("foo"); import * as Foo from "ambient"; import bar from "ambient"; diff --git a/tests/baselines/reference/moduleElementsInWrongContext2.js b/tests/baselines/reference/moduleElementsInWrongContext2.js index cc4aca0dec02a..8582213a6ae2f 100644 --- a/tests/baselines/reference/moduleElementsInWrongContext2.js +++ b/tests/baselines/reference/moduleElementsInWrongContext2.js @@ -45,7 +45,7 @@ function blah() { return C; }()); export default C; - function bee() { } + export function bee() { } import I2 = require("foo"); import * as Foo from "ambient"; import bar from "ambient"; diff --git a/tests/baselines/reference/parserModifierOnStatementInBlock3.js b/tests/baselines/reference/parserModifierOnStatementInBlock3.js index 2815af43708ba..9f2cdf6850f8b 100644 --- a/tests/baselines/reference/parserModifierOnStatementInBlock3.js +++ b/tests/baselines/reference/parserModifierOnStatementInBlock3.js @@ -8,7 +8,7 @@ export function foo() { //// [parserModifierOnStatementInBlock3.js] "use strict"; function foo() { - function bar() { + export function bar() { } } exports.foo = foo; diff --git a/tests/baselines/reference/parserModifierOnStatementInBlock4.js b/tests/baselines/reference/parserModifierOnStatementInBlock4.js index 34b390468eb93..ba2d256aeb96c 100644 --- a/tests/baselines/reference/parserModifierOnStatementInBlock4.js +++ b/tests/baselines/reference/parserModifierOnStatementInBlock4.js @@ -7,6 +7,6 @@ //// [parserModifierOnStatementInBlock4.js] { - function bar() { + export function bar() { } }