@@ -16996,16 +16996,19 @@ namespace ts {
16996
16996
return isReachableFlowNodeWorker(flow, /*skipCacheCheck*/ false);
16997
16997
}
16998
16998
16999
- function isReachableFlowNodeWorker(flow: FlowNode, skipCacheCheck : boolean): boolean {
16999
+ function isReachableFlowNodeWorker(flow: FlowNode, noCacheCheck : boolean): boolean {
17000
17000
while (true) {
17001
17001
const flags = flow.flags;
17002
- if (flags & FlowFlags.Shared && !skipCacheCheck) {
17003
- const id = getFlowNodeId(flow);
17004
- const reachable = flowNodeReachable[id];
17005
- return reachable !== undefined ? reachable : (flowNodeReachable[id] = isReachableFlowNodeWorker(flow, /*skipCacheCheck*/ true));
17002
+ if (flags & FlowFlags.Shared | flags & FlowFlags.SwitchClause) {
17003
+ if (!noCacheCheck) {
17004
+ const id = getFlowNodeId(flow);
17005
+ const reachable = flowNodeReachable[id];
17006
+ return reachable !== undefined ? reachable : (flowNodeReachable[id] = isReachableFlowNodeWorker(flow, /*skipCacheCheck*/ true));
17007
+ }
17008
+ noCacheCheck = false;
17006
17009
}
17007
- if (flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.SwitchClause | FlowFlags. ArrayMutation | FlowFlags.PreFinally | FlowFlags.AfterFinally)) {
17008
- flow = (<FlowAssignment | FlowCondition | FlowSwitchClause | FlowArrayMutation | PreFinallyFlow | AfterFinallyFlow>flow).antecedent;
17010
+ if (flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.ArrayMutation | FlowFlags.PreFinally | FlowFlags.AfterFinally)) {
17011
+ flow = (<FlowAssignment | FlowCondition | FlowArrayMutation | PreFinallyFlow | AfterFinallyFlow>flow).antecedent;
17009
17012
}
17010
17013
else if (flags & FlowFlags.Call) {
17011
17014
const signature = getEffectsSignature((<FlowCall>flow).node);
@@ -17014,14 +17017,20 @@ namespace ts {
17014
17017
}
17015
17018
flow = (<FlowCall>flow).antecedent;
17016
17019
}
17020
+ else if (flags & FlowFlags.BranchLabel) {
17021
+ return some((<FlowLabel>flow).antecedents!, isReachableFlowNode);
17022
+ }
17017
17023
else if (flags & FlowFlags.LoopLabel) {
17018
17024
flow = (<FlowLabel>flow).antecedents![0];
17019
17025
}
17020
- else if (flags & FlowFlags.BranchLabel) {
17021
- return every((<FlowLabel>flow).antecedents!, isReachableFlowNode);
17026
+ else if (flags & FlowFlags.SwitchClause) {
17027
+ if ((<FlowSwitchClause>flow).clauseStart === (<FlowSwitchClause>flow).clauseEnd && isExhaustiveSwitchStatement((<FlowSwitchClause>flow).switchStatement)) {
17028
+ return false;
17029
+ }
17030
+ flow = (<FlowSwitchClause>flow).antecedent;
17022
17031
}
17023
17032
else {
17024
- return true ;
17033
+ return !(flags & FlowFlags.Unreachable) ;
17025
17034
}
17026
17035
}
17027
17036
}
@@ -17044,7 +17053,11 @@ namespace ts {
17044
17053
// on empty arrays are possible without implicit any errors and new element types can be inferred without
17045
17054
// type mismatch errors.
17046
17055
const resultType = getObjectFlags(evolvedType) & ObjectFlags.EvolvingArray && isEvolvingArrayOperationTarget(reference) ? autoArrayType : finalizeEvolvingArrayType(evolvedType);
17047
- if (resultType === unreachableNeverType || reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) {
17056
+ if (resultType === unreachableNeverType) {
17057
+ error(reference, Diagnostics.Unreachable_code_detected);
17058
+ return declaredType;
17059
+ }
17060
+ if (reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) {
17048
17061
return declaredType;
17049
17062
}
17050
17063
return resultType;
@@ -23804,9 +23817,7 @@ namespace ts {
23804
23817
}
23805
23818
23806
23819
function functionHasImplicitReturn(func: FunctionLikeDeclaration) {
23807
- return !!(func.flags & NodeFlags.HasImplicitReturn &&
23808
- !some((<Block>func.body).statements, s => s.kind === SyntaxKind.SwitchStatement && isExhaustiveSwitchStatement(<SwitchStatement>s)) &&
23809
- !(func.returnFlowNode && !isReachableFlowNode(func.returnFlowNode)));
23820
+ return func.endFlowNode && isReachableFlowNode(func.endFlowNode);
23810
23821
}
23811
23822
23812
23823
/** NOTE: Return value of `[]` means a different thing than `undefined`. `[]` means func returns `void`, `undefined` means it returns `never`. */
0 commit comments