Skip to content

Commit cf4bb58

Browse files
authored
Omit effects-free conditional constructs from control flow graph (microsoft#58013)
1 parent 5144b3e commit cf4bb58

File tree

1 file changed

+39
-11
lines changed

1 file changed

+39
-11
lines changed

src/compiler/binder.ts

+39-11
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ import {
146146
isDeclarationStatement,
147147
isDestructuringAssignment,
148148
isDottedName,
149-
isElementAccessExpression,
150149
isEmptyObjectLiteral,
151150
isEntityNameExpression,
152151
isEnumConst,
@@ -188,7 +187,6 @@ import {
188187
isModuleExportsAccessExpression,
189188
isNamedDeclaration,
190189
isNamespaceExport,
191-
isNonNullExpression,
192190
isNullishCoalesce,
193191
isObjectLiteralExpression,
194192
isObjectLiteralMethod,
@@ -540,6 +538,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
540538
var preSwitchCaseFlow: FlowNode | undefined;
541539
var activeLabelList: ActiveLabel | undefined;
542540
var hasExplicitReturn: boolean;
541+
var hasFlowEffects: boolean;
543542

544543
// state used for emit helpers
545544
var emitFlags: NodeFlags;
@@ -618,6 +617,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
618617
currentExceptionTarget = undefined;
619618
activeLabelList = undefined;
620619
hasExplicitReturn = false;
620+
hasFlowEffects = false;
621621
inAssignmentPattern = false;
622622
emitFlags = NodeFlags.None;
623623
}
@@ -1223,8 +1223,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
12231223
function isNarrowingExpression(expr: Expression): boolean {
12241224
switch (expr.kind) {
12251225
case SyntaxKind.Identifier:
1226-
case SyntaxKind.PrivateIdentifier:
12271226
case SyntaxKind.ThisKeyword:
1227+
return true;
12281228
case SyntaxKind.PropertyAccessExpression:
12291229
case SyntaxKind.ElementAccessExpression:
12301230
return containsNarrowableReference(expr);
@@ -1248,11 +1248,24 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
12481248
}
12491249

12501250
function isNarrowableReference(expr: Expression): boolean {
1251-
return isDottedName(expr)
1252-
|| (isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression)
1253-
|| isBinaryExpression(expr) && expr.operatorToken.kind === SyntaxKind.CommaToken && isNarrowableReference(expr.right)
1254-
|| isElementAccessExpression(expr) && (isStringOrNumericLiteralLike(expr.argumentExpression) || isEntityNameExpression(expr.argumentExpression)) && isNarrowableReference(expr.expression)
1255-
|| isAssignmentExpression(expr) && isNarrowableReference(expr.left);
1251+
switch (expr.kind) {
1252+
case SyntaxKind.Identifier:
1253+
case SyntaxKind.ThisKeyword:
1254+
case SyntaxKind.SuperKeyword:
1255+
case SyntaxKind.MetaProperty:
1256+
return true;
1257+
case SyntaxKind.PropertyAccessExpression:
1258+
case SyntaxKind.ParenthesizedExpression:
1259+
case SyntaxKind.NonNullExpression:
1260+
return isNarrowableReference((expr as PropertyAccessExpression | ParenthesizedExpression | NonNullExpression).expression);
1261+
case SyntaxKind.ElementAccessExpression:
1262+
return (isStringOrNumericLiteralLike((expr as ElementAccessExpression).argumentExpression) || isEntityNameExpression((expr as ElementAccessExpression).argumentExpression)) &&
1263+
isNarrowableReference((expr as ElementAccessExpression).expression);
1264+
case SyntaxKind.BinaryExpression:
1265+
return (expr as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken && isNarrowableReference((expr as BinaryExpression).right) ||
1266+
isAssignmentOperator((expr as BinaryExpression).operatorToken.kind) && isLeftHandSideExpression((expr as BinaryExpression).left);
1267+
}
1268+
return false;
12561269
}
12571270

12581271
function containsNarrowableReference(expr: Expression): boolean {
@@ -1371,6 +1384,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
13711384

13721385
function createFlowMutation(flags: FlowFlags, antecedent: FlowNode, node: Expression | VariableDeclaration | ArrayBindingElement): FlowNode {
13731386
setFlowNodeReferenced(antecedent);
1387+
hasFlowEffects = true;
13741388
const result = initFlowNode({ flags, antecedent, node });
13751389
if (currentExceptionTarget) {
13761390
addAntecedent(currentExceptionTarget, result);
@@ -1380,6 +1394,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
13801394

13811395
function createFlowCall(antecedent: FlowNode, node: CallExpression): FlowNode {
13821396
setFlowNodeReferenced(antecedent);
1397+
hasFlowEffects = true;
13831398
return initFlowNode({ flags: FlowFlags.Call, antecedent, node });
13841399
}
13851400

@@ -1559,6 +1574,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
15591574
}
15601575
}
15611576
currentFlow = unreachableFlow;
1577+
hasFlowEffects = true;
15621578
}
15631579

15641580
function findActiveLabel(name: __String) {
@@ -1575,6 +1591,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
15751591
if (flowLabel) {
15761592
addAntecedent(flowLabel, currentFlow);
15771593
currentFlow = unreachableFlow;
1594+
hasFlowEffects = true;
15781595
}
15791596
}
15801597

@@ -1904,8 +1921,12 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
19041921
if (isLogicalOrCoalescingBinaryOperator(operator) || isLogicalOrCoalescingAssignmentOperator(operator)) {
19051922
if (isTopLevelLogicalExpression(node)) {
19061923
const postExpressionLabel = createBranchLabel();
1924+
const saveCurrentFlow = currentFlow;
1925+
const saveHasFlowEffects = hasFlowEffects;
1926+
hasFlowEffects = false;
19071927
bindLogicalLikeExpression(node, postExpressionLabel, postExpressionLabel);
1908-
currentFlow = finishFlowLabel(postExpressionLabel);
1928+
currentFlow = hasFlowEffects ? finishFlowLabel(postExpressionLabel) : saveCurrentFlow;
1929+
hasFlowEffects ||= saveHasFlowEffects;
19091930
}
19101931
else {
19111932
bindLogicalLikeExpression(node, currentTrueTarget!, currentFalseTarget!);
@@ -1985,6 +2006,9 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
19852006
const trueLabel = createBranchLabel();
19862007
const falseLabel = createBranchLabel();
19872008
const postExpressionLabel = createBranchLabel();
2009+
const saveCurrentFlow = currentFlow;
2010+
const saveHasFlowEffects = hasFlowEffects;
2011+
hasFlowEffects = false;
19882012
bindCondition(node.condition, trueLabel, falseLabel);
19892013
currentFlow = finishFlowLabel(trueLabel);
19902014
bind(node.questionToken);
@@ -1994,7 +2018,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
19942018
bind(node.colonToken);
19952019
bind(node.whenFalse);
19962020
addAntecedent(postExpressionLabel, currentFlow);
1997-
currentFlow = finishFlowLabel(postExpressionLabel);
2021+
currentFlow = hasFlowEffects ? finishFlowLabel(postExpressionLabel) : saveCurrentFlow;
2022+
hasFlowEffects ||= saveHasFlowEffects;
19982023
}
19992024

20002025
function bindInitializedVariableFlow(node: VariableDeclaration | ArrayBindingElement) {
@@ -2134,8 +2159,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
21342159
function bindOptionalChainFlow(node: OptionalChain) {
21352160
if (isTopLevelLogicalExpression(node)) {
21362161
const postExpressionLabel = createBranchLabel();
2162+
const saveCurrentFlow = currentFlow;
2163+
const saveHasFlowEffects = hasFlowEffects;
21372164
bindOptionalChain(node, postExpressionLabel, postExpressionLabel);
2138-
currentFlow = finishFlowLabel(postExpressionLabel);
2165+
currentFlow = hasFlowEffects ? finishFlowLabel(postExpressionLabel) : saveCurrentFlow;
2166+
hasFlowEffects ||= saveHasFlowEffects;
21392167
}
21402168
else {
21412169
bindOptionalChain(node, currentTrueTarget!, currentFalseTarget!);

0 commit comments

Comments
 (0)