Skip to content

Commit d5b9263

Browse files
committed
Consolidate destructuring code paths
1 parent 8babde0 commit d5b9263

25 files changed

+857
-1364
lines changed

src/compiler/binder.ts

Lines changed: 76 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,31 @@ namespace ts {
570570
}
571571
}
572572

573+
function bindEach(nodes: NodeArray<Node>) {
574+
if (nodes === undefined) {
575+
return;
576+
}
577+
578+
if (skipTransformFlagAggregation) {
579+
forEach(nodes, bind);
580+
}
581+
else {
582+
const savedSubtreeTransformFlags = subtreeTransformFlags;
583+
subtreeTransformFlags = TransformFlags.None;
584+
let nodeArrayFlags = TransformFlags.None;
585+
for (const node of nodes) {
586+
bind(node);
587+
nodeArrayFlags |= node.transformFlags & ~TransformFlags.HasComputedFlags;
588+
}
589+
nodes.transformFlags = nodeArrayFlags | TransformFlags.HasComputedFlags;
590+
subtreeTransformFlags |= savedSubtreeTransformFlags;
591+
}
592+
}
593+
594+
function bindEachChild(node: Node) {
595+
forEachChild(node, bind, bindEach);
596+
}
597+
573598
function bindChildrenWorker(node: Node): void {
574599
// Binding of JsDocComment should be done before the current block scope container changes.
575600
// because the scope of JsDocComment should not be affected by whether the current node is a
@@ -578,7 +603,7 @@ namespace ts {
578603
forEach(node.jsDocComments, bind);
579604
}
580605
if (checkUnreachable(node)) {
581-
forEachChild(node, bind);
606+
bindEachChild(node);
582607
return;
583608
}
584609
switch (node.kind) {
@@ -643,7 +668,7 @@ namespace ts {
643668
bindCallExpressionFlow(<CallExpression>node);
644669
break;
645670
default:
646-
forEachChild(node, bind);
671+
bindEachChild(node);
647672
break;
648673
}
649674
}
@@ -976,7 +1001,7 @@ namespace ts {
9761001
return undefined;
9771002
}
9781003

979-
function bindbreakOrContinueFlow(node: BreakOrContinueStatement, breakTarget: FlowLabel, continueTarget: FlowLabel) {
1004+
function bindBreakOrContinueFlow(node: BreakOrContinueStatement, breakTarget: FlowLabel, continueTarget: FlowLabel) {
9801005
const flowLabel = node.kind === SyntaxKind.BreakStatement ? breakTarget : continueTarget;
9811006
if (flowLabel) {
9821007
addAntecedent(flowLabel, currentFlow);
@@ -990,11 +1015,11 @@ namespace ts {
9901015
const activeLabel = findActiveLabel(node.label.text);
9911016
if (activeLabel) {
9921017
activeLabel.referenced = true;
993-
bindbreakOrContinueFlow(node, activeLabel.breakTarget, activeLabel.continueTarget);
1018+
bindBreakOrContinueFlow(node, activeLabel.breakTarget, activeLabel.continueTarget);
9941019
}
9951020
}
9961021
else {
997-
bindbreakOrContinueFlow(node, currentBreakTarget, currentContinueTarget);
1022+
bindBreakOrContinueFlow(node, currentBreakTarget, currentContinueTarget);
9981023
}
9991024
}
10001025

@@ -1062,6 +1087,8 @@ namespace ts {
10621087
}
10631088

10641089
function bindCaseBlock(node: CaseBlock): void {
1090+
const savedSubtreeTransformFlags = subtreeTransformFlags;
1091+
subtreeTransformFlags = 0;
10651092
const clauses = node.clauses;
10661093
let fallthroughFlow = unreachableFlow;
10671094
for (let i = 0; i < clauses.length; i++) {
@@ -1081,14 +1108,16 @@ namespace ts {
10811108
errorOnFirstToken(clause, Diagnostics.Fallthrough_case_in_switch);
10821109
}
10831110
}
1111+
clauses.transformFlags = subtreeTransformFlags | TransformFlags.HasComputedFlags;
1112+
subtreeTransformFlags |= savedSubtreeTransformFlags;
10841113
}
10851114

10861115
function bindCaseClause(node: CaseClause): void {
10871116
const saveCurrentFlow = currentFlow;
10881117
currentFlow = preSwitchCaseFlow;
10891118
bind(node.expression);
10901119
currentFlow = saveCurrentFlow;
1091-
forEach(node.statements, bind);
1120+
bindEach(node.statements);
10921121
}
10931122

10941123
function pushActiveLabel(name: string, breakTarget: FlowLabel, continueTarget: FlowLabel): ActiveLabel {
@@ -1180,20 +1209,20 @@ namespace ts {
11801209
const saveTrueTarget = currentTrueTarget;
11811210
currentTrueTarget = currentFalseTarget;
11821211
currentFalseTarget = saveTrueTarget;
1183-
forEachChild(node, bind);
1212+
bindEachChild(node);
11841213
currentFalseTarget = currentTrueTarget;
11851214
currentTrueTarget = saveTrueTarget;
11861215
}
11871216
else {
1188-
forEachChild(node, bind);
1217+
bindEachChild(node);
11891218
if (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) {
11901219
bindAssignmentTargetFlow(node.operand);
11911220
}
11921221
}
11931222
}
11941223

11951224
function bindPostfixUnaryExpressionFlow(node: PostfixUnaryExpression) {
1196-
forEachChild(node, bind);
1225+
bindEachChild(node);
11971226
if (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) {
11981227
bindAssignmentTargetFlow(node.operand);
11991228
}
@@ -1212,7 +1241,7 @@ namespace ts {
12121241
}
12131242
}
12141243
else {
1215-
forEachChild(node, bind);
1244+
bindEachChild(node);
12161245
if (isAssignmentOperator(operator) && !isAssignmentTarget(node)) {
12171246
bindAssignmentTargetFlow(node.left);
12181247
if (operator === SyntaxKind.EqualsToken && node.left.kind === SyntaxKind.ElementAccessExpression) {
@@ -1226,7 +1255,7 @@ namespace ts {
12261255
}
12271256

12281257
function bindDeleteExpressionFlow(node: DeleteExpression) {
1229-
forEachChild(node, bind);
1258+
bindEachChild(node);
12301259
if (node.expression.kind === SyntaxKind.PropertyAccessExpression) {
12311260
bindAssignmentTargetFlow(node.expression);
12321261
}
@@ -1261,7 +1290,7 @@ namespace ts {
12611290
}
12621291

12631292
function bindVariableDeclarationFlow(node: VariableDeclaration) {
1264-
forEachChild(node, bind);
1293+
bindEachChild(node);
12651294
if (node.initializer || node.parent.parent.kind === SyntaxKind.ForInStatement || node.parent.parent.kind === SyntaxKind.ForOfStatement) {
12661295
bindInitializedVariableFlow(node);
12671296
}
@@ -1276,12 +1305,12 @@ namespace ts {
12761305
expr = (<ParenthesizedExpression>expr).expression;
12771306
}
12781307
if (expr.kind === SyntaxKind.FunctionExpression || expr.kind === SyntaxKind.ArrowFunction) {
1279-
forEach(node.typeArguments, bind);
1280-
forEach(node.arguments, bind);
1308+
bindEach(node.typeArguments);
1309+
bindEach(node.arguments);
12811310
bind(node.expression);
12821311
}
12831312
else {
1284-
forEachChild(node, bind);
1313+
bindEachChild(node);
12851314
}
12861315
if (node.expression.kind === SyntaxKind.PropertyAccessExpression) {
12871316
const propertyAccess = <PropertyAccessExpression>node.expression;
@@ -2514,7 +2543,7 @@ namespace ts {
25142543
transformFlags |= TransformFlags.AssertTypeScript;
25152544
}
25162545

2517-
if (subtreeFlags & TransformFlags.ContainsSpreadExpression
2546+
if (subtreeFlags & TransformFlags.ContainsSpread
25182547
|| isSuperOrSuperProperty(expression, expressionKind)) {
25192548
// If the this node contains a SpreadExpression, or is a super call, then it is an ES6
25202549
// node.
@@ -2545,7 +2574,7 @@ namespace ts {
25452574
if (node.typeArguments) {
25462575
transformFlags |= TransformFlags.AssertTypeScript;
25472576
}
2548-
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
2577+
if (subtreeFlags & TransformFlags.ContainsSpread) {
25492578
// If the this node contains a SpreadElementExpression then it is an ES6
25502579
// node.
25512580
transformFlags |= TransformFlags.AssertES2015;
@@ -2554,7 +2583,6 @@ namespace ts {
25542583
return transformFlags & ~TransformFlags.ArrayLiteralOrCallOrNewExcludes;
25552584
}
25562585

2557-
25582586
function computeBinaryExpression(node: BinaryExpression, subtreeFlags: TransformFlags) {
25592587
let transformFlags = subtreeFlags;
25602588
const operatorTokenKind = node.operatorToken.kind;
@@ -2601,7 +2629,7 @@ namespace ts {
26012629
}
26022630

26032631
// parameters with object rest destructuring are ES Next syntax
2604-
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
2632+
if (subtreeFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) {
26052633
transformFlags |= TransformFlags.AssertESNext;
26062634
}
26072635

@@ -2723,7 +2751,7 @@ namespace ts {
27232751
}
27242752

27252753
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
2726-
return transformFlags & ~TransformFlags.NodeExcludes;
2754+
return transformFlags & ~TransformFlags.CatchClauseExcludes;
27272755
}
27282756

27292757
function computeExpressionWithTypeArguments(node: ExpressionWithTypeArguments, subtreeFlags: TransformFlags) {
@@ -2839,7 +2867,7 @@ namespace ts {
28392867
}
28402868

28412869
// function declarations with object rest destructuring are ES Next syntax
2842-
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
2870+
if (subtreeFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) {
28432871
transformFlags |= TransformFlags.AssertESNext;
28442872
}
28452873

@@ -2881,7 +2909,7 @@ namespace ts {
28812909
}
28822910

28832911
// function expressions with object rest destructuring are ES Next syntax
2884-
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
2912+
if (subtreeFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) {
28852913
transformFlags |= TransformFlags.AssertESNext;
28862914
}
28872915

@@ -2924,7 +2952,7 @@ namespace ts {
29242952
}
29252953

29262954
// arrow functions with object rest destructuring are ES Next syntax
2927-
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
2955+
if (subtreeFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest)) {
29282956
transformFlags |= TransformFlags.AssertESNext;
29292957
}
29302958

@@ -3178,16 +3206,19 @@ namespace ts {
31783206
break;
31793207

31803208
case SyntaxKind.SpreadElement:
3209+
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsSpread;
3210+
break;
3211+
31813212
case SyntaxKind.SpreadAssignment:
3182-
// This node is ES6 or ES next syntax, but is handled by a containing node.
3183-
transformFlags |= TransformFlags.ContainsSpreadExpression;
3213+
transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsSpread | TransformFlags.ContainsObjectSpread;
31843214
break;
31853215

31863216
case SyntaxKind.BindingElement:
3187-
if ((node as BindingElement).dotDotDotToken) {
3188-
// this node is ES2015 or ES next syntax, but is handled by a containing node.
3189-
transformFlags |= TransformFlags.ContainsSpreadExpression;
3217+
transformFlags |= TransformFlags.AssertES2015;
3218+
if ((<BindingElement>node).dotDotDotToken) {
3219+
transformFlags |= TransformFlags.ContainsRest;
31903220
}
3221+
break;
31913222

31923223
case SyntaxKind.SuperKeyword:
31933224
// This node is ES6 syntax.
@@ -3200,14 +3231,16 @@ namespace ts {
32003231
break;
32013232

32023233
case SyntaxKind.ObjectBindingPattern:
3203-
case SyntaxKind.ArrayBindingPattern:
3204-
// These nodes are ES2015 or ES Next syntax.
3205-
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
3206-
transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsBindingPattern;
3207-
}
3208-
else {
3209-
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
3234+
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
3235+
if (subtreeFlags & TransformFlags.ContainsSpread) {
3236+
transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsObjectRest;
32103237
}
3238+
excludeFlags = TransformFlags.BindingPatternExcludes;
3239+
break;
3240+
3241+
case SyntaxKind.ArrayBindingPattern:
3242+
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
3243+
excludeFlags = TransformFlags.BindingPatternExcludes;
32113244
break;
32123245

32133246
case SyntaxKind.Decorator:
@@ -3229,18 +3262,18 @@ namespace ts {
32293262
transformFlags |= TransformFlags.ContainsLexicalThis;
32303263
}
32313264

3232-
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
3265+
if (subtreeFlags & TransformFlags.ContainsSpread) {
32333266
// If an ObjectLiteralExpression contains a spread element, then it
32343267
// is an ES next node.
3235-
transformFlags |= TransformFlags.AssertESNext;
3268+
transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsObjectSpread;
32363269
}
32373270

32383271
break;
32393272

32403273
case SyntaxKind.ArrayLiteralExpression:
32413274
case SyntaxKind.NewExpression:
32423275
excludeFlags = TransformFlags.ArrayLiteralOrCallOrNewExcludes;
3243-
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
3276+
if (subtreeFlags & TransformFlags.ContainsSpread) {
32443277
// If the this node contains a SpreadExpression, then it is an ES6
32453278
// node.
32463279
transformFlags |= TransformFlags.AssertES2015;
@@ -3333,6 +3366,11 @@ namespace ts {
33333366
return TransformFlags.TypeExcludes;
33343367
case SyntaxKind.ObjectLiteralExpression:
33353368
return TransformFlags.ObjectLiteralExcludes;
3369+
case SyntaxKind.CatchClause:
3370+
return TransformFlags.CatchClauseExcludes;
3371+
case SyntaxKind.ObjectBindingPattern:
3372+
case SyntaxKind.ArrayBindingPattern:
3373+
return TransformFlags.BindingPatternExcludes;
33363374
default:
33373375
return TransformFlags.NodeExcludes;
33383376
}

0 commit comments

Comments
 (0)