@@ -146,7 +146,6 @@ import {
146
146
isDeclarationStatement ,
147
147
isDestructuringAssignment ,
148
148
isDottedName ,
149
- isElementAccessExpression ,
150
149
isEmptyObjectLiteral ,
151
150
isEntityNameExpression ,
152
151
isEnumConst ,
@@ -188,7 +187,6 @@ import {
188
187
isModuleExportsAccessExpression ,
189
188
isNamedDeclaration ,
190
189
isNamespaceExport ,
191
- isNonNullExpression ,
192
190
isNullishCoalesce ,
193
191
isObjectLiteralExpression ,
194
192
isObjectLiteralMethod ,
@@ -540,6 +538,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
540
538
var preSwitchCaseFlow : FlowNode | undefined ;
541
539
var activeLabelList : ActiveLabel | undefined ;
542
540
var hasExplicitReturn : boolean ;
541
+ var hasFlowEffects : boolean ;
543
542
544
543
// state used for emit helpers
545
544
var emitFlags : NodeFlags ;
@@ -618,6 +617,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
618
617
currentExceptionTarget = undefined ;
619
618
activeLabelList = undefined ;
620
619
hasExplicitReturn = false ;
620
+ hasFlowEffects = false ;
621
621
inAssignmentPattern = false ;
622
622
emitFlags = NodeFlags . None ;
623
623
}
@@ -1223,8 +1223,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1223
1223
function isNarrowingExpression ( expr : Expression ) : boolean {
1224
1224
switch ( expr . kind ) {
1225
1225
case SyntaxKind . Identifier :
1226
- case SyntaxKind . PrivateIdentifier :
1227
1226
case SyntaxKind . ThisKeyword :
1227
+ return true ;
1228
1228
case SyntaxKind . PropertyAccessExpression :
1229
1229
case SyntaxKind . ElementAccessExpression :
1230
1230
return containsNarrowableReference ( expr ) ;
@@ -1248,11 +1248,24 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1248
1248
}
1249
1249
1250
1250
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 ;
1256
1269
}
1257
1270
1258
1271
function containsNarrowableReference ( expr : Expression ) : boolean {
@@ -1371,6 +1384,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1371
1384
1372
1385
function createFlowMutation ( flags : FlowFlags , antecedent : FlowNode , node : Expression | VariableDeclaration | ArrayBindingElement ) : FlowNode {
1373
1386
setFlowNodeReferenced ( antecedent ) ;
1387
+ hasFlowEffects = true ;
1374
1388
const result = initFlowNode ( { flags, antecedent, node } ) ;
1375
1389
if ( currentExceptionTarget ) {
1376
1390
addAntecedent ( currentExceptionTarget , result ) ;
@@ -1380,6 +1394,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1380
1394
1381
1395
function createFlowCall ( antecedent : FlowNode , node : CallExpression ) : FlowNode {
1382
1396
setFlowNodeReferenced ( antecedent ) ;
1397
+ hasFlowEffects = true ;
1383
1398
return initFlowNode ( { flags : FlowFlags . Call , antecedent, node } ) ;
1384
1399
}
1385
1400
@@ -1559,6 +1574,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1559
1574
}
1560
1575
}
1561
1576
currentFlow = unreachableFlow ;
1577
+ hasFlowEffects = true ;
1562
1578
}
1563
1579
1564
1580
function findActiveLabel ( name : __String ) {
@@ -1575,6 +1591,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1575
1591
if ( flowLabel ) {
1576
1592
addAntecedent ( flowLabel , currentFlow ) ;
1577
1593
currentFlow = unreachableFlow ;
1594
+ hasFlowEffects = true ;
1578
1595
}
1579
1596
}
1580
1597
@@ -1904,8 +1921,12 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1904
1921
if ( isLogicalOrCoalescingBinaryOperator ( operator ) || isLogicalOrCoalescingAssignmentOperator ( operator ) ) {
1905
1922
if ( isTopLevelLogicalExpression ( node ) ) {
1906
1923
const postExpressionLabel = createBranchLabel ( ) ;
1924
+ const saveCurrentFlow = currentFlow ;
1925
+ const saveHasFlowEffects = hasFlowEffects ;
1926
+ hasFlowEffects = false ;
1907
1927
bindLogicalLikeExpression ( node , postExpressionLabel , postExpressionLabel ) ;
1908
- currentFlow = finishFlowLabel ( postExpressionLabel ) ;
1928
+ currentFlow = hasFlowEffects ? finishFlowLabel ( postExpressionLabel ) : saveCurrentFlow ;
1929
+ hasFlowEffects ||= saveHasFlowEffects ;
1909
1930
}
1910
1931
else {
1911
1932
bindLogicalLikeExpression ( node , currentTrueTarget ! , currentFalseTarget ! ) ;
@@ -1985,6 +2006,9 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1985
2006
const trueLabel = createBranchLabel ( ) ;
1986
2007
const falseLabel = createBranchLabel ( ) ;
1987
2008
const postExpressionLabel = createBranchLabel ( ) ;
2009
+ const saveCurrentFlow = currentFlow ;
2010
+ const saveHasFlowEffects = hasFlowEffects ;
2011
+ hasFlowEffects = false ;
1988
2012
bindCondition ( node . condition , trueLabel , falseLabel ) ;
1989
2013
currentFlow = finishFlowLabel ( trueLabel ) ;
1990
2014
bind ( node . questionToken ) ;
@@ -1994,7 +2018,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
1994
2018
bind ( node . colonToken ) ;
1995
2019
bind ( node . whenFalse ) ;
1996
2020
addAntecedent ( postExpressionLabel , currentFlow ) ;
1997
- currentFlow = finishFlowLabel ( postExpressionLabel ) ;
2021
+ currentFlow = hasFlowEffects ? finishFlowLabel ( postExpressionLabel ) : saveCurrentFlow ;
2022
+ hasFlowEffects ||= saveHasFlowEffects ;
1998
2023
}
1999
2024
2000
2025
function bindInitializedVariableFlow ( node : VariableDeclaration | ArrayBindingElement ) {
@@ -2134,8 +2159,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
2134
2159
function bindOptionalChainFlow ( node : OptionalChain ) {
2135
2160
if ( isTopLevelLogicalExpression ( node ) ) {
2136
2161
const postExpressionLabel = createBranchLabel ( ) ;
2162
+ const saveCurrentFlow = currentFlow ;
2163
+ const saveHasFlowEffects = hasFlowEffects ;
2137
2164
bindOptionalChain ( node , postExpressionLabel , postExpressionLabel ) ;
2138
- currentFlow = finishFlowLabel ( postExpressionLabel ) ;
2165
+ currentFlow = hasFlowEffects ? finishFlowLabel ( postExpressionLabel ) : saveCurrentFlow ;
2166
+ hasFlowEffects ||= saveHasFlowEffects ;
2139
2167
}
2140
2168
else {
2141
2169
bindOptionalChain ( node , currentTrueTarget ! , currentFalseTarget ! ) ;
0 commit comments