Skip to content

Commit f7311ef

Browse files
authored
Merge pull request microsoft#23956 from Kingwl/emit-var-at-top
emit temporary vars at the top of the scope
2 parents 7271ec1 + ad5a4c7 commit f7311ef

File tree

307 files changed

+11385
-11307
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

307 files changed

+11385
-11307
lines changed

src/compiler/core.ts

+15
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,21 @@ namespace ts {
951951
return to;
952952
}
953953

954+
/**
955+
* Appends a range of value to begin of an array, returning the array.
956+
*
957+
* @param to The array to which `value` is to be appended. If `to` is `undefined`, a new array
958+
* is created if `value` was appended.
959+
* @param from The values to append to the array. If `from` is `undefined`, nothing is
960+
* appended. If an element of `from` is `undefined`, that element is not appended.
961+
*/
962+
export function prependRange<T>(to: T[], from: ReadonlyArray<T> | undefined): T[] | undefined {
963+
if (from === undefined || from.length === 0) return to;
964+
if (to === undefined) return from.slice();
965+
to.unshift(...from);
966+
return to;
967+
}
968+
954969
/**
955970
* @return Whether the value was added.
956971
*/

src/compiler/transformers/es2015.ts

+11-9
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ namespace ts {
529529
createVariableStatement(/*modifiers*/ undefined,
530530
createVariableDeclarationList(taggedTemplateStringDeclarations)));
531531
}
532-
addRange(statements, endLexicalEnvironment());
532+
prependRange(statements, endLexicalEnvironment());
533533
exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
534534
return updateSourceFileNode(
535535
node,
@@ -836,7 +836,7 @@ namespace ts {
836836
setEmitFlags(statement, EmitFlags.NoComments | EmitFlags.NoTokenSourceMaps);
837837
statements.push(statement);
838838

839-
addRange(statements, endLexicalEnvironment());
839+
prependRange(statements, endLexicalEnvironment());
840840

841841
const block = createBlock(setTextRange(createNodeArray(statements), /*location*/ node.members), /*multiLine*/ true);
842842
setEmitFlags(block, EmitFlags.NoComments);
@@ -979,7 +979,7 @@ namespace ts {
979979
);
980980
}
981981

982-
addRange(statements, endLexicalEnvironment());
982+
prependRange(statements, endLexicalEnvironment());
983983

984984
if (constructor) {
985985
prependCaptureNewTargetIfNeeded(statements, constructor, /*copyOnWrite*/ false);
@@ -1894,7 +1894,7 @@ namespace ts {
18941894
}
18951895

18961896
const lexicalEnvironment = context.endLexicalEnvironment();
1897-
addRange(statements, lexicalEnvironment);
1897+
prependRange(statements, lexicalEnvironment);
18981898

18991899
prependCaptureNewTargetIfNeeded(statements, node, /*copyOnWrite*/ false);
19001900

@@ -2712,7 +2712,7 @@ namespace ts {
27122712
if (loopOutParameters.length) {
27132713
copyOutParameters(loopOutParameters, CopyDirection.ToOutParameter, statements);
27142714
}
2715-
addRange(statements, lexicalEnvironment);
2715+
prependRange(statements, lexicalEnvironment);
27162716
loopBody = createBlock(statements, /*multiline*/ true);
27172717
}
27182718

@@ -3309,10 +3309,12 @@ namespace ts {
33093309
// expression, but we will restore them later to preserve comments and source maps.
33103310
const body = cast(cast(skipOuterExpressions(node.expression), isArrowFunction).body, isBlock);
33113311

3312-
// The class statements are the statements generated by visiting the first statement of the
3312+
// The class statements are the statements generated by visiting the first statement with initializer of the
33133313
// body (1), while all other statements are added to remainingStatements (2)
3314-
const classStatements = visitNodes(body.statements, visitor, isStatement, 0, 1);
3315-
const remainingStatements = visitNodes(body.statements, visitor, isStatement, 1, body.statements.length - 1);
3314+
const isVariableStatementWithInitializer = (stmt: Statement) => isVariableStatement(stmt) && !!firstOrUndefined(stmt.declarationList.declarations).initializer;
3315+
const bodyStatements = visitNodes(body.statements, visitor, isStatement);
3316+
const classStatements = filter(bodyStatements, isVariableStatementWithInitializer);
3317+
const remainingStatements = filter(bodyStatements, stmt => !isVariableStatementWithInitializer(stmt));
33163318
const varStatement = cast(firstOrUndefined(classStatements), isVariableStatement);
33173319

33183320
// We know there is only one variable declaration here as we verified this in an
@@ -3324,6 +3326,7 @@ namespace ts {
33243326
// we see as an assignment, for example:
33253327
//
33263328
// (function () {
3329+
// var C_1;
33273330
// var C = C_1 = (function () {
33283331
// function C() {
33293332
// }
@@ -3332,7 +3335,6 @@ namespace ts {
33323335
// }());
33333336
// C = C_1 = __decorate([dec], C);
33343337
// return C;
3335-
// var C_1;
33363338
// }())
33373339
//
33383340
const aliasAssignment = tryCast(initializer, isAssignmentExpression);

src/compiler/transformers/es2017.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ namespace ts {
412412
)
413413
);
414414

415-
addRange(statements, endLexicalEnvironment());
415+
prependRange(statements, endLexicalEnvironment());
416416

417417
const block = createBlock(statements, /*multiLine*/ true);
418418
setTextRange(block, node.body);
@@ -443,7 +443,7 @@ namespace ts {
443443
const declarations = endLexicalEnvironment();
444444
if (some(declarations)) {
445445
const block = convertToFunctionBody(expression);
446-
result = updateBlock(block, setTextRange(createNodeArray(concatenate(block.statements, declarations)), block.statements));
446+
result = updateBlock(block, setTextRange(createNodeArray(concatenate(declarations, block.statements)), block.statements));
447447
}
448448
else {
449449
result = expression;

src/compiler/transformers/esnext.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ namespace ts {
663663
)
664664
);
665665

666-
addRange(statements, endLexicalEnvironment());
666+
prependRange(statements, endLexicalEnvironment());
667667
const block = updateBlock(node.body, statements);
668668

669669
// Minor optimization, emit `_super` helper to capture `super` access in an arrow.
@@ -692,11 +692,11 @@ namespace ts {
692692
statementOffset = addPrologue(statements, body.statements, /*ensureUseStrict*/ false, visitor);
693693
}
694694
addRange(statements, appendObjectRestAssignmentsIfNeeded(/*statements*/ undefined, node));
695-
const trailingStatements = endLexicalEnvironment();
696-
if (statementOffset > 0 || some(statements) || some(trailingStatements)) {
695+
const leadingStatements = endLexicalEnvironment();
696+
if (statementOffset > 0 || some(statements) || some(leadingStatements)) {
697697
const block = convertToFunctionBody(body, /*multiLine*/ true);
698+
prependRange(statements, leadingStatements);
698699
addRange(statements, block.statements.slice(statementOffset));
699-
addRange(statements, trailingStatements);
700700
return updateBlock(block, setTextRange(createNodeArray(statements), block.statements));
701701
}
702702
return body;

src/compiler/transformers/generators.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ namespace ts {
586586
transformAndEmitStatements(body.statements, statementOffset);
587587

588588
const buildResult = build();
589-
addRange(statements, endLexicalEnvironment());
589+
prependRange(statements, endLexicalEnvironment());
590590
statements.push(createReturn(buildResult));
591591

592592
// Restore previous generator state

src/compiler/transformers/module/module.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ namespace ts {
9797
append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement));
9898
addRange(statements, visitNodes(node.statements, sourceElementVisitor, isStatement, statementOffset));
9999
addExportEqualsIfNeeded(statements, /*emitAsReturn*/ false);
100-
addRange(statements, endLexicalEnvironment());
100+
prependRange(statements, endLexicalEnvironment());
101101

102102
const updated = updateSourceFileNode(node, setTextRange(createNodeArray(statements), node.statements));
103103
if (currentModuleInfo.hasExportStarsToExportValues && !compilerOptions.importHelpers) {
@@ -426,7 +426,7 @@ namespace ts {
426426

427427
// End the lexical environment for the module body
428428
// and merge any new lexical declarations.
429-
addRange(statements, endLexicalEnvironment());
429+
prependRange(statements, endLexicalEnvironment());
430430

431431
const body = createBlock(statements, /*multiLine*/ true);
432432
if (currentModuleInfo.hasExportStarsToExportValues && !compilerOptions.importHelpers) {

src/compiler/transformers/module/system.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ namespace ts {
257257
// We emit hoisted variables early to align roughly with our previous emit output.
258258
// Two key differences in this approach are:
259259
// - Temporary variables will appear at the top rather than at the bottom of the file
260-
addRange(statements, endLexicalEnvironment());
260+
prependRange(statements, endLexicalEnvironment());
261261

262262
const exportStarFunction = addExportStarIfNeeded(statements);
263263
const moduleObject = createObjectLiteral([

src/compiler/transformers/ts.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ namespace ts {
669669
setEmitFlags(statement, EmitFlags.NoComments | EmitFlags.NoTokenSourceMaps);
670670
statements.push(statement);
671671

672-
addRange(statements, context.endLexicalEnvironment());
672+
prependRange(statements, context.endLexicalEnvironment());
673673

674674
const iife = createImmediatelyInvokedArrowFunction(statements);
675675
setEmitFlags(iife, EmitFlags.TypeScriptClassWrapper);
@@ -2685,8 +2685,9 @@ namespace ts {
26852685

26862686
const statements: Statement[] = [];
26872687
startLexicalEnvironment();
2688-
addRange(statements, map(node.members, transformEnumMember));
2689-
addRange(statements, endLexicalEnvironment());
2688+
const members = map(node.members, transformEnumMember);
2689+
prependRange(statements, endLexicalEnvironment());
2690+
addRange(statements, members);
26902691

26912692
currentNamespaceContainerName = savedCurrentNamespaceLocalName;
26922693
return createBlock(
@@ -3000,7 +3001,7 @@ namespace ts {
30003001
statementsLocation = moveRangePos(moduleBlock.statements, -1);
30013002
}
30023003

3003-
addRange(statements, endLexicalEnvironment());
3004+
prependRange(statements, endLexicalEnvironment());
30043005
currentNamespaceContainerName = savedCurrentNamespaceContainerName;
30053006
currentNamespace = savedCurrentNamespace;
30063007
currentScopeFirstDeclarationsOfName = savedCurrentScopeFirstDeclarationsOfName;

src/compiler/visitor.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ namespace ts {
145145
statements = setTextRange(createNodeArray([createStatement(createLiteral("use strict")), ...statements]), statements);
146146
}
147147
const declarations = context.endLexicalEnvironment();
148-
return setTextRange(createNodeArray(concatenate(statements, declarations)), statements);
148+
return setTextRange(createNodeArray(concatenate(declarations, statements)), statements);
149149
}
150150

151151
/**
@@ -1468,8 +1468,8 @@ namespace ts {
14681468
}
14691469

14701470
return isNodeArray(statements)
1471-
? setTextRange(createNodeArray(concatenate(statements, declarations)), statements)
1472-
: addRange(statements, declarations);
1471+
? setTextRange(createNodeArray(concatenate(declarations, statements)), statements)
1472+
: prependRange(statements, declarations);
14731473
}
14741474

14751475
/**

tests/baselines/reference/ES5For-of30.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ for ([a = 1, b = ""] of tuple) {
77
}
88

99
//// [ES5For-of30.js]
10+
var _a, _b, _c;
1011
var a, b;
1112
var tuple = [2, "3"];
1213
for (var _i = 0, tuple_1 = tuple; _i < tuple_1.length; _i++) {
1314
_a = tuple_1[_i], _b = _a[0], a = _b === void 0 ? 1 : _b, _c = _a[1], b = _c === void 0 ? "" : _c;
1415
a;
1516
b;
1617
}
17-
var _a, _b, _c;

tests/baselines/reference/ES5For-of31.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ for ({ a: b = 1, b: a = ""} of []) {
77
}
88

99
//// [ES5For-of31.js]
10+
var _a, _b, _c;
1011
var a, b;
11-
for (var _i = 0, _a = []; _i < _a.length; _i++) {
12-
_b = _a[_i], _c = _b.a, b = _c === void 0 ? 1 : _c, _d = _b.b, a = _d === void 0 ? "" : _d;
12+
for (var _i = 0, _d = []; _i < _d.length; _i++) {
13+
_a = _d[_i], _b = _a.a, b = _b === void 0 ? 1 : _b, _c = _a.b, a = _c === void 0 ? "" : _c;
1314
a;
1415
b;
1516
}
16-
var _b, _c, _d;

tests/baselines/reference/ES5For-of33.js

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/baselines/reference/ES5For-of33.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/baselines/reference/ES5For-of33.sourcemap.txt

+32-32
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ sourceFile:ES5For-of33.ts
1818
>>> }
1919
>>> };
2020
>>>};
21+
>>>var e_1, _a;
2122
>>>try {
22-
>>> for (var _a = __values(['a', 'b', 'c']), _b = _a.next(); !_b.done; _b = _a.next()) {
23+
>>> for (var _b = __values(['a', 'b', 'c']), _c = _b.next(); !_c.done; _c = _b.next()) {
2324
1 >^^^^
2425
2 > ^^^^^
2526
3 > ^^^^
@@ -50,23 +51,23 @@ sourceFile:ES5For-of33.ts
5051
13>
5152
14>
5253
15> )
53-
1 >Emitted(12, 5) Source(1, 1) + SourceIndex(0)
54-
2 >Emitted(12, 10) Source(1, 15) + SourceIndex(0)
55-
3 >Emitted(12, 14) Source(1, 15) + SourceIndex(0)
56-
4 >Emitted(12, 19) Source(1, 15) + SourceIndex(0)
57-
5 >Emitted(12, 28) Source(1, 15) + SourceIndex(0)
58-
6 >Emitted(12, 29) Source(1, 16) + SourceIndex(0)
59-
7 >Emitted(12, 32) Source(1, 19) + SourceIndex(0)
60-
8 >Emitted(12, 34) Source(1, 21) + SourceIndex(0)
61-
9 >Emitted(12, 37) Source(1, 24) + SourceIndex(0)
62-
10>Emitted(12, 39) Source(1, 26) + SourceIndex(0)
63-
11>Emitted(12, 42) Source(1, 29) + SourceIndex(0)
64-
12>Emitted(12, 43) Source(1, 30) + SourceIndex(0)
65-
13>Emitted(12, 44) Source(1, 30) + SourceIndex(0)
66-
14>Emitted(12, 60) Source(1, 30) + SourceIndex(0)
67-
15>Emitted(12, 88) Source(1, 32) + SourceIndex(0)
54+
1 >Emitted(13, 5) Source(1, 1) + SourceIndex(0)
55+
2 >Emitted(13, 10) Source(1, 15) + SourceIndex(0)
56+
3 >Emitted(13, 14) Source(1, 15) + SourceIndex(0)
57+
4 >Emitted(13, 19) Source(1, 15) + SourceIndex(0)
58+
5 >Emitted(13, 28) Source(1, 15) + SourceIndex(0)
59+
6 >Emitted(13, 29) Source(1, 16) + SourceIndex(0)
60+
7 >Emitted(13, 32) Source(1, 19) + SourceIndex(0)
61+
8 >Emitted(13, 34) Source(1, 21) + SourceIndex(0)
62+
9 >Emitted(13, 37) Source(1, 24) + SourceIndex(0)
63+
10>Emitted(13, 39) Source(1, 26) + SourceIndex(0)
64+
11>Emitted(13, 42) Source(1, 29) + SourceIndex(0)
65+
12>Emitted(13, 43) Source(1, 30) + SourceIndex(0)
66+
13>Emitted(13, 44) Source(1, 30) + SourceIndex(0)
67+
14>Emitted(13, 60) Source(1, 30) + SourceIndex(0)
68+
15>Emitted(13, 88) Source(1, 32) + SourceIndex(0)
6869
---
69-
>>> var v = _b.value;
70+
>>> var v = _c.value;
7071
1 >^^^^^^^^
7172
2 > ^^^^
7273
3 > ^
@@ -75,10 +76,10 @@ sourceFile:ES5For-of33.ts
7576
2 > var
7677
3 > v
7778
4 >
78-
1 >Emitted(13, 9) Source(1, 6) + SourceIndex(0)
79-
2 >Emitted(13, 13) Source(1, 10) + SourceIndex(0)
80-
3 >Emitted(13, 14) Source(1, 11) + SourceIndex(0)
81-
4 >Emitted(13, 25) Source(1, 11) + SourceIndex(0)
79+
1 >Emitted(14, 9) Source(1, 6) + SourceIndex(0)
80+
2 >Emitted(14, 13) Source(1, 10) + SourceIndex(0)
81+
3 >Emitted(14, 14) Source(1, 11) + SourceIndex(0)
82+
4 >Emitted(14, 25) Source(1, 11) + SourceIndex(0)
8283
---
8384
>>> console.log(v);
8485
1 >^^^^^^^^
@@ -98,28 +99,27 @@ sourceFile:ES5For-of33.ts
9899
6 > v
99100
7 > )
100101
8 > ;
101-
1 >Emitted(14, 9) Source(2, 5) + SourceIndex(0)
102-
2 >Emitted(14, 16) Source(2, 12) + SourceIndex(0)
103-
3 >Emitted(14, 17) Source(2, 13) + SourceIndex(0)
104-
4 >Emitted(14, 20) Source(2, 16) + SourceIndex(0)
105-
5 >Emitted(14, 21) Source(2, 17) + SourceIndex(0)
106-
6 >Emitted(14, 22) Source(2, 18) + SourceIndex(0)
107-
7 >Emitted(14, 23) Source(2, 19) + SourceIndex(0)
108-
8 >Emitted(14, 24) Source(2, 20) + SourceIndex(0)
102+
1 >Emitted(15, 9) Source(2, 5) + SourceIndex(0)
103+
2 >Emitted(15, 16) Source(2, 12) + SourceIndex(0)
104+
3 >Emitted(15, 17) Source(2, 13) + SourceIndex(0)
105+
4 >Emitted(15, 20) Source(2, 16) + SourceIndex(0)
106+
5 >Emitted(15, 21) Source(2, 17) + SourceIndex(0)
107+
6 >Emitted(15, 22) Source(2, 18) + SourceIndex(0)
108+
7 >Emitted(15, 23) Source(2, 19) + SourceIndex(0)
109+
8 >Emitted(15, 24) Source(2, 20) + SourceIndex(0)
109110
---
110111
>>> }
111112
1 >^^^^^
112113
1 >
113114
>}
114-
1 >Emitted(15, 6) Source(3, 2) + SourceIndex(0)
115+
1 >Emitted(16, 6) Source(3, 2) + SourceIndex(0)
115116
---
116117
>>>}
117118
>>>catch (e_1_1) { e_1 = { error: e_1_1 }; }
118119
>>>finally {
119120
>>> try {
120-
>>> if (_b && !_b.done && (_c = _a["return"])) _c.call(_a);
121+
>>> if (_c && !_c.done && (_a = _b["return"])) _a.call(_b);
121122
>>> }
122123
>>> finally { if (e_1) throw e_1.error; }
123124
>>>}
124-
>>>var e_1, _c;
125125
>>>//# sourceMappingURL=ES5For-of33.js.map

0 commit comments

Comments
 (0)