Code following truthiness assertion with false argument is unreachable

This commit is contained in:
Anders Hejlsberg
2019-10-04 12:30:02 -07:00
parent 3c794e9f9b
commit feed4b9b53

View File

@@ -18790,6 +18790,22 @@ namespace ts {
return !(flow.flags & FlowFlags.PreFinally && (<PreFinallyFlow>flow).lock.locked) && isReachableFlowNodeWorker(flow, /*skipCacheCheck*/ false);
}
function isFalseExpression(expr: Expression): boolean {
const node = skipParentheses(expr);
if (node.kind === SyntaxKind.FalseKeyword) {
return true;
}
if (node.kind === SyntaxKind.BinaryExpression) {
if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
return isFalseExpression((<BinaryExpression>node).left) || isFalseExpression((<BinaryExpression>node).right);
}
if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken) {
return isFalseExpression((<BinaryExpression>node).left) && isFalseExpression((<BinaryExpression>node).right);
}
}
return false;
}
function isReachableFlowNodeWorker(flow: FlowNode, noCacheCheck: boolean): boolean {
while (true) {
if (flow === lastFlowNode) {
@@ -18809,8 +18825,17 @@ namespace ts {
}
else if (flags & FlowFlags.Call) {
const signature = getEffectsSignature((<FlowCall>flow).node);
if (signature && getReturnTypeOfSignature(signature).flags & TypeFlags.Never) {
return false;
if (signature) {
const predicate = getTypePredicateOfSignature(signature);
if (predicate && predicate.kind === TypePredicateKind.AssertsIdentifier) {
const predicateArgument = (<FlowCall>flow).node.arguments[predicate.parameterIndex];
if (predicateArgument && isFalseExpression(predicateArgument)) {
return false;
}
}
if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) {
return false;
}
}
flow = (<FlowCall>flow).antecedent;
}
@@ -19049,6 +19074,9 @@ namespace ts {
function narrowTypeByAssertion(type: Type, expr: Expression): Type {
const node = skipParentheses(expr);
if (node.kind === SyntaxKind.FalseKeyword) {
return unreachableNeverType;
}
if (node.kind === SyntaxKind.BinaryExpression) {
if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
return narrowTypeByAssertion(narrowTypeByAssertion(type, (<BinaryExpression>node).left), (<BinaryExpression>node).right);
@@ -19068,7 +19096,7 @@ namespace ts {
const flowType = getTypeAtFlowNode(flow.antecedent);
const type = getTypeFromFlowType(flowType);
const narrowedType = predicate.type ? narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) :
predicate.kind === TypePredicateKind.AssertsIdentifier ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) :
predicate.kind === TypePredicateKind.AssertsIdentifier && predicate.parameterIndex < flow.node.arguments.length ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) :
type;
return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType));
}