Skip to content

Commit 8a599f6

Browse files
authored
Merge pull request microsoft#14090 from Microsoft/es5-emit-param-initialiser-before-object-rest
ES5:Emit parameter initialiser before object rest destructuring
2 parents 014845a + 58a6c92 commit 8a599f6

21 files changed

Lines changed: 558 additions & 20 deletions

src/compiler/factory.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3058,15 +3058,26 @@ namespace ts {
30583058
* @param ensureUseStrict: boolean determining whether the function need to add prologue-directives
30593059
* @param visitor: Optional callback used to visit any custom prologue directives.
30603060
*/
3061-
export function addPrologueDirectives(target: Statement[], source: Statement[], ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult<Node>): number {
3061+
export function addPrologue(target: Statement[], source: Statement[], ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult<Node>): number {
3062+
const offset = addStandardPrologue(target, source, ensureUseStrict);
3063+
return addCustomPrologue(target, source, offset, visitor);
3064+
}
3065+
3066+
/**
3067+
* Add just the standard (string-expression) prologue-directives into target statement-array.
3068+
* The function needs to be called during each transformation step.
3069+
* This function needs to be called whenever we transform the statement
3070+
* list of a source file, namespace, or function-like body.
3071+
*/
3072+
export function addStandardPrologue(target: Statement[], source: Statement[], ensureUseStrict?: boolean): number {
30623073
Debug.assert(target.length === 0, "Prologue directives should be at the first statement in the target statements array");
30633074
let foundUseStrict = false;
30643075
let statementOffset = 0;
30653076
const numStatements = source.length;
30663077
while (statementOffset < numStatements) {
30673078
const statement = source[statementOffset];
30683079
if (isPrologueDirective(statement)) {
3069-
if (isUseStrictPrologue(statement as ExpressionStatement)) {
3080+
if (isUseStrictPrologue(statement)) {
30703081
foundUseStrict = true;
30713082
}
30723083
target.push(statement);
@@ -3079,6 +3090,17 @@ namespace ts {
30793090
if (ensureUseStrict && !foundUseStrict) {
30803091
target.push(startOnNewLine(createStatement(createLiteral("use strict"))));
30813092
}
3093+
return statementOffset;
3094+
}
3095+
3096+
/**
3097+
* Add just the custom prologue-directives into target statement-array.
3098+
* The function needs to be called during each transformation step.
3099+
* This function needs to be called whenever we transform the statement
3100+
* list of a source file, namespace, or function-like body.
3101+
*/
3102+
export function addCustomPrologue(target: Statement[], source: Statement[], statementOffset: number, visitor?: (node: Node) => VisitResult<Node>): number {
3103+
const numStatements = source.length;
30823104
while (statementOffset < numStatements) {
30833105
const statement = source[statementOffset];
30843106
if (getEmitFlags(statement) & EmitFlags.CustomPrologue) {

src/compiler/transformers/es2015.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -515,8 +515,9 @@ namespace ts {
515515
const ancestorFacts = enterSubtree(HierarchyFacts.SourceFileExcludes, HierarchyFacts.SourceFileIncludes);
516516
const statements: Statement[] = [];
517517
startLexicalEnvironment();
518-
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ false, visitor);
518+
let statementOffset = addStandardPrologue(statements, node.statements, /*ensureUseStrict*/ false);
519519
addCaptureThisForNodeIfNeeded(statements, node);
520+
statementOffset = addCustomPrologue(statements, node.statements, statementOffset, visitor);
520521
addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));
521522
addRange(statements, endLexicalEnvironment());
522523
exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
@@ -924,13 +925,16 @@ namespace ts {
924925
statementOffset = 0;
925926
}
926927
else if (constructor) {
927-
// Otherwise, try to emit all potential prologue directives first.
928-
statementOffset = addPrologueDirectives(statements, constructor.body.statements, /*ensureUseStrict*/ false, visitor);
928+
statementOffset = addStandardPrologue(statements, constructor.body.statements, /*ensureUseStrict*/ false);
929929
}
930930

931931
if (constructor) {
932932
addDefaultValueAssignmentsIfNeeded(statements, constructor);
933933
addRestParameterIfNeeded(statements, constructor, hasSynthesizedSuper);
934+
if (!hasSynthesizedSuper) {
935+
// If no super call has been synthesized, emit custom prologue directives.
936+
statementOffset = addCustomPrologue(statements, constructor.body.statements, statementOffset, visitor);
937+
}
934938
Debug.assert(statementOffset >= 0, "statementOffset not initialized correctly!");
935939

936940
}
@@ -1821,8 +1825,8 @@ namespace ts {
18211825
resumeLexicalEnvironment();
18221826
if (isBlock(body)) {
18231827
// ensureUseStrict is false because no new prologue-directive should be added.
1824-
// addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array
1825-
statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor);
1828+
// addStandardPrologue will put already-existing directives at the beginning of the target statement-array
1829+
statementOffset = addStandardPrologue(statements, body.statements, /*ensureUseStrict*/ false);
18261830
}
18271831

18281832
addCaptureThisForNodeIfNeeded(statements, node);
@@ -1835,6 +1839,9 @@ namespace ts {
18351839
}
18361840

18371841
if (isBlock(body)) {
1842+
// addCustomPrologue puts already-existing directives at the beginning of the target statement-array
1843+
statementOffset = addCustomPrologue(statements, body.statements, statementOffset, visitor);
1844+
18381845
statementsLocation = body.statements;
18391846
addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset));
18401847

src/compiler/transformers/es2017.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ namespace ts {
222222

223223
if (!isArrowFunction) {
224224
const statements: Statement[] = [];
225-
const statementOffset = addPrologueDirectives(statements, (<Block>node.body).statements, /*ensureUseStrict*/ false, visitor);
225+
const statementOffset = addPrologue(statements, (<Block>node.body).statements, /*ensureUseStrict*/ false, visitor);
226226
statements.push(
227227
createReturn(
228228
createAwaiterHelper(

src/compiler/transformers/esnext.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ namespace ts {
618618
function transformAsyncGeneratorFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody {
619619
resumeLexicalEnvironment();
620620
const statements: Statement[] = [];
621-
const statementOffset = addPrologueDirectives(statements, node.body.statements, /*ensureUseStrict*/ false, visitor);
621+
const statementOffset = addPrologue(statements, node.body.statements, /*ensureUseStrict*/ false, visitor);
622622
appendObjectRestAssignmentsIfNeeded(statements, node);
623623

624624
statements.push(
@@ -663,12 +663,19 @@ namespace ts {
663663
function transformFunctionBody(node: ArrowFunction): ConciseBody;
664664
function transformFunctionBody(node: FunctionLikeDeclaration): ConciseBody {
665665
resumeLexicalEnvironment();
666-
const leadingStatements = appendObjectRestAssignmentsIfNeeded(/*statements*/ undefined, node);
666+
let statementOffset = 0;
667+
const statements: Statement[] = [];
667668
const body = visitNode(node.body, visitor, isConciseBody);
669+
if (isBlock(body)) {
670+
statementOffset = addPrologue(statements, body.statements, /*ensureUseStrict*/ false, visitor);
671+
}
672+
addRange(statements, appendObjectRestAssignmentsIfNeeded(/*statements*/ undefined, node));
668673
const trailingStatements = endLexicalEnvironment();
669-
if (some(leadingStatements) || some(trailingStatements)) {
674+
if (statementOffset > 0 || some(statements) || some(trailingStatements)) {
670675
const block = convertToFunctionBody(body, /*multiLine*/ true);
671-
return updateBlock(block, setTextRange(createNodeArray(concatenate(concatenate(leadingStatements, block.statements), trailingStatements)), block.statements));
676+
addRange(statements, block.statements.slice(statementOffset));
677+
addRange(statements, trailingStatements);
678+
return updateBlock(block, setTextRange(createNodeArray(statements), block.statements));
672679
}
673680
return body;
674681
}

src/compiler/transformers/generators.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ namespace ts {
587587
// Build the generator
588588
resumeLexicalEnvironment();
589589

590-
const statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor);
590+
const statementOffset = addPrologue(statements, body.statements, /*ensureUseStrict*/ false, visitor);
591591

592592
transformAndEmitStatements(body.statements, statementOffset);
593593

src/compiler/transformers/module/es2015.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace ts {
2424
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(node, compilerOptions);
2525
if (externalHelpersModuleName) {
2626
const statements: Statement[] = [];
27-
const statementOffset = addPrologueDirectives(statements, node.statements);
27+
const statementOffset = addPrologue(statements, node.statements);
2828
append(statements,
2929
createImportDeclaration(
3030
/*decorators*/ undefined,

src/compiler/transformers/module/module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ namespace ts {
9090

9191
const statements: Statement[] = [];
9292
const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile));
93-
const statementOffset = addPrologueDirectives(statements, node.statements, ensureUseStrict, sourceElementVisitor);
93+
const statementOffset = addPrologue(statements, node.statements, ensureUseStrict, sourceElementVisitor);
9494

9595
if (shouldEmitUnderscoreUnderscoreESModule()) {
9696
append(statements, createUnderscoreUnderscoreESModule());
@@ -388,7 +388,7 @@ namespace ts {
388388
startLexicalEnvironment();
389389

390390
const statements: Statement[] = [];
391-
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
391+
const statementOffset = addPrologue(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
392392

393393
if (shouldEmitUnderscoreUnderscoreESModule()) {
394394
append(statements, createUnderscoreUnderscoreESModule());

src/compiler/transformers/module/system.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ namespace ts {
228228

229229
// Add any prologue directives.
230230
const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile));
231-
const statementOffset = addPrologueDirectives(statements, node.statements, ensureUseStrict, sourceElementVisitor);
231+
const statementOffset = addPrologue(statements, node.statements, ensureUseStrict, sourceElementVisitor);
232232

233233
// var __moduleName = context_1 && context_1.id;
234234
statements.push(

src/compiler/transformers/ts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,7 @@ namespace ts {
954954
if (ctor.body) {
955955
const statements = ctor.body.statements;
956956
// add prologue directives to the list (if any)
957-
const index = addPrologueDirectives(result, statements, /*ensureUseStrict*/ false, visitor);
957+
const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor);
958958
if (index === statements.length) {
959959
// list contains nothing but prologue directives (or empty) - exit
960960
return index;

tests/baselines/reference/objectRestParameter.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ class C {
1414
// actually, never mind, don't clone
1515
}
1616
}
17-
17+
function foobar({ bar={}, ...opts }: any = {}) {
18+
}
19+
foobar();
20+
foobar({ baz: 'hello' });
21+
foobar({ bar: { greeting: 'hello' } });
1822

1923

2024
//// [objectRestParameter.js]
@@ -48,3 +52,9 @@ class C {
4852
// actually, never mind, don't clone
4953
}
5054
}
55+
function foobar(_a = {}) {
56+
var { bar = {} } = _a, opts = __rest(_a, ["bar"]);
57+
}
58+
foobar();
59+
foobar({ baz: 'hello' });
60+
foobar({ bar: { greeting: 'hello' } });

0 commit comments

Comments
 (0)