Skip to content

Commit feed4b9

Browse files
committed
Code following truthiness assertion with false argument is unreachable
1 parent 3c794e9 commit feed4b9

File tree

1 file changed

+31
-3
lines changed

1 file changed

+31
-3
lines changed

src/compiler/checker.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18790,6 +18790,22 @@ namespace ts {
1879018790
return !(flow.flags & FlowFlags.PreFinally && (<PreFinallyFlow>flow).lock.locked) && isReachableFlowNodeWorker(flow, /*skipCacheCheck*/ false);
1879118791
}
1879218792

18793+
function isFalseExpression(expr: Expression): boolean {
18794+
const node = skipParentheses(expr);
18795+
if (node.kind === SyntaxKind.FalseKeyword) {
18796+
return true;
18797+
}
18798+
if (node.kind === SyntaxKind.BinaryExpression) {
18799+
if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
18800+
return isFalseExpression((<BinaryExpression>node).left) || isFalseExpression((<BinaryExpression>node).right);
18801+
}
18802+
if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken) {
18803+
return isFalseExpression((<BinaryExpression>node).left) && isFalseExpression((<BinaryExpression>node).right);
18804+
}
18805+
}
18806+
return false;
18807+
}
18808+
1879318809
function isReachableFlowNodeWorker(flow: FlowNode, noCacheCheck: boolean): boolean {
1879418810
while (true) {
1879518811
if (flow === lastFlowNode) {
@@ -18809,8 +18825,17 @@ namespace ts {
1880918825
}
1881018826
else if (flags & FlowFlags.Call) {
1881118827
const signature = getEffectsSignature((<FlowCall>flow).node);
18812-
if (signature && getReturnTypeOfSignature(signature).flags & TypeFlags.Never) {
18813-
return false;
18828+
if (signature) {
18829+
const predicate = getTypePredicateOfSignature(signature);
18830+
if (predicate && predicate.kind === TypePredicateKind.AssertsIdentifier) {
18831+
const predicateArgument = (<FlowCall>flow).node.arguments[predicate.parameterIndex];
18832+
if (predicateArgument && isFalseExpression(predicateArgument)) {
18833+
return false;
18834+
}
18835+
}
18836+
if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) {
18837+
return false;
18838+
}
1881418839
}
1881518840
flow = (<FlowCall>flow).antecedent;
1881618841
}
@@ -19049,6 +19074,9 @@ namespace ts {
1904919074

1905019075
function narrowTypeByAssertion(type: Type, expr: Expression): Type {
1905119076
const node = skipParentheses(expr);
19077+
if (node.kind === SyntaxKind.FalseKeyword) {
19078+
return unreachableNeverType;
19079+
}
1905219080
if (node.kind === SyntaxKind.BinaryExpression) {
1905319081
if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
1905419082
return narrowTypeByAssertion(narrowTypeByAssertion(type, (<BinaryExpression>node).left), (<BinaryExpression>node).right);
@@ -19068,7 +19096,7 @@ namespace ts {
1906819096
const flowType = getTypeAtFlowNode(flow.antecedent);
1906919097
const type = getTypeFromFlowType(flowType);
1907019098
const narrowedType = predicate.type ? narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) :
19071-
predicate.kind === TypePredicateKind.AssertsIdentifier ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) :
19099+
predicate.kind === TypePredicateKind.AssertsIdentifier && predicate.parameterIndex < flow.node.arguments.length ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) :
1907219100
type;
1907319101
return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType));
1907419102
}

0 commit comments

Comments
 (0)