Skip to content

Commit ed33801

Browse files
committed
Use silent never type in control flow loop analysis
1 parent 9f22bad commit ed33801

File tree

1 file changed

+36
-6
lines changed

1 file changed

+36
-6
lines changed

src/compiler/checker.ts

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ namespace ts {
132132
const esSymbolType = createIntrinsicType(TypeFlags.ESSymbol, "symbol");
133133
const voidType = createIntrinsicType(TypeFlags.Void, "void");
134134
const neverType = createIntrinsicType(TypeFlags.Never, "never");
135+
const silentNeverType = createIntrinsicType(TypeFlags.Never, "never");
135136

136137
const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
137138
const emptyGenericType = <GenericType><ObjectType>createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
@@ -147,6 +148,7 @@ namespace ts {
147148
const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
148149
const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
149150
const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
151+
const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
150152

151153
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
152154

@@ -8070,6 +8072,9 @@ namespace ts {
80708072
// we remove type string.
80718073
function getAssignmentReducedType(declaredType: UnionType, assignedType: Type) {
80728074
if (declaredType !== assignedType) {
8075+
if (assignedType.flags & TypeFlags.Never) {
8076+
return assignedType;
8077+
}
80738078
const reducedType = filterType(declaredType, t => typeMaybeAssignableTo(assignedType, t));
80748079
if (!(reducedType.flags & TypeFlags.Never)) {
80758080
return reducedType;
@@ -8445,12 +8450,13 @@ namespace ts {
84458450
// attempt to narrow the antecedent type. If that produces the never type, and if
84468451
// the antecedent type is incomplete (i.e. a transient type in a loop), then we
84478452
// take the type guard as an indication that control *could* reach here once we
8448-
// have the complete type. We proceed by reverting to the declared type and then
8449-
// narrow that.
8453+
// have the complete type. We proceed by switching to the silent never type which
8454+
// doesn't report errors when operators are applied to it. Note that this is the
8455+
// *only* place a silent never type is ever generated.
84508456
const assumeTrue = (flow.flags & FlowFlags.TrueCondition) !== 0;
84518457
type = narrowType(type, flow.expression, assumeTrue);
84528458
if (type.flags & TypeFlags.Never && isIncomplete(flowType)) {
8453-
type = narrowType(declaredType, flow.expression, assumeTrue);
8459+
type = silentNeverType;
84548460
}
84558461
}
84568462
return createFlowType(type, isIncomplete(flowType));
@@ -10889,7 +10895,7 @@ namespace ts {
1088910895

1089010896
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
1089110897
const type = checkNonNullExpression(left);
10892-
if (isTypeAny(type)) {
10898+
if (isTypeAny(type) || type === silentNeverType) {
1089310899
return type;
1089410900
}
1089510901

@@ -11036,8 +11042,8 @@ namespace ts {
1103611042
const objectType = getApparentType(checkNonNullExpression(node.expression));
1103711043
const indexType = node.argumentExpression ? checkExpression(node.argumentExpression) : unknownType;
1103811044

11039-
if (objectType === unknownType) {
11040-
return unknownType;
11045+
if (objectType === unknownType || objectType === silentNeverType) {
11046+
return objectType;
1104111047
}
1104211048

1104311049
const isConstEnum = isConstEnumObjectType(objectType);
@@ -12087,6 +12093,9 @@ namespace ts {
1208712093
}
1208812094

1208912095
const funcType = checkNonNullExpression(node.expression);
12096+
if (funcType === silentNeverType) {
12097+
return silentNeverSignature;
12098+
}
1209012099
const apparentType = getApparentType(funcType);
1209112100

1209212101
if (apparentType === unknownType) {
@@ -12159,6 +12168,9 @@ namespace ts {
1215912168
}
1216012169

1216112170
let expressionType = checkNonNullExpression(node.expression);
12171+
if (expressionType === silentNeverType) {
12172+
return silentNeverSignature;
12173+
}
1216212174

1216312175
// If expressionType's apparent type(section 3.8.1) is an object type with one or
1216412176
// more construct signatures, the expression is processed in the same manner as a
@@ -13024,6 +13036,9 @@ namespace ts {
1302413036

1302513037
function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type {
1302613038
const operandType = checkExpression(node.operand);
13039+
if (operandType === silentNeverType) {
13040+
return silentNeverType;
13041+
}
1302713042
if (node.operator === SyntaxKind.MinusToken && node.operand.kind === SyntaxKind.NumericLiteral) {
1302813043
return getLiteralTypeForText(TypeFlags.NumberLiteral, "" + -(<LiteralExpression>node.operand).text);
1302913044
}
@@ -13057,6 +13072,9 @@ namespace ts {
1305713072

1305813073
function checkPostfixUnaryExpression(node: PostfixUnaryExpression): Type {
1305913074
const operandType = checkExpression(node.operand);
13075+
if (operandType === silentNeverType) {
13076+
return silentNeverType;
13077+
}
1306013078
const ok = checkArithmeticOperandType(node.operand, getNonNullableType(operandType),
1306113079
Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type);
1306213080
if (ok) {
@@ -13121,6 +13139,9 @@ namespace ts {
1312113139
}
1312213140

1312313141
function checkInstanceOfExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type {
13142+
if (leftType === silentNeverType || rightType === silentNeverType) {
13143+
return silentNeverType;
13144+
}
1312413145
// TypeScript 1.0 spec (April 2014): 4.15.4
1312513146
// The instanceof operator requires the left operand to be of type Any, an object type, or a type parameter type,
1312613147
// and the right operand to be of type Any or a subtype of the 'Function' interface type.
@@ -13137,6 +13158,9 @@ namespace ts {
1313713158
}
1313813159

1313913160
function checkInExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type {
13161+
if (leftType === silentNeverType || rightType === silentNeverType) {
13162+
return silentNeverType;
13163+
}
1314013164
// TypeScript 1.0 spec (April 2014): 4.15.5
1314113165
// The in operator requires the left operand to be of type Any, the String primitive type, or the Number primitive type,
1314213166
// and the right operand to be of type Any, an object type, or a type parameter type.
@@ -13401,6 +13425,9 @@ namespace ts {
1340113425
case SyntaxKind.CaretEqualsToken:
1340213426
case SyntaxKind.AmpersandToken:
1340313427
case SyntaxKind.AmpersandEqualsToken:
13428+
if (leftType === silentNeverType || rightType === silentNeverType) {
13429+
return silentNeverType;
13430+
}
1340413431
// TypeScript 1.0 spec (April 2014): 4.19.1
1340513432
// These operators require their operands to be of type Any, the Number primitive type,
1340613433
// or an enum type. Operands of an enum type are treated
@@ -13433,6 +13460,9 @@ namespace ts {
1343313460
return numberType;
1343413461
case SyntaxKind.PlusToken:
1343513462
case SyntaxKind.PlusEqualsToken:
13463+
if (leftType === silentNeverType || rightType === silentNeverType) {
13464+
return silentNeverType;
13465+
}
1343613466
// TypeScript 1.0 spec (April 2014): 4.19.2
1343713467
// The binary + operator requires both operands to be of the Number primitive type or an enum type,
1343813468
// or at least one of the operands to be of type Any or the String primitive type.

0 commit comments

Comments
 (0)