Use silent never type in control flow loop analysis
This commit is contained in:
parent
9f22bad4ba
commit
ed338013e0
1 changed files with 36 additions and 6 deletions
|
@ -132,6 +132,7 @@ namespace ts {
|
||||||
const esSymbolType = createIntrinsicType(TypeFlags.ESSymbol, "symbol");
|
const esSymbolType = createIntrinsicType(TypeFlags.ESSymbol, "symbol");
|
||||||
const voidType = createIntrinsicType(TypeFlags.Void, "void");
|
const voidType = createIntrinsicType(TypeFlags.Void, "void");
|
||||||
const neverType = createIntrinsicType(TypeFlags.Never, "never");
|
const neverType = createIntrinsicType(TypeFlags.Never, "never");
|
||||||
|
const silentNeverType = createIntrinsicType(TypeFlags.Never, "never");
|
||||||
|
|
||||||
const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
||||||
const emptyGenericType = <GenericType><ObjectType>createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
const emptyGenericType = <GenericType><ObjectType>createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
||||||
|
@ -147,6 +148,7 @@ namespace ts {
|
||||||
const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
||||||
const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
||||||
const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
||||||
|
const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
||||||
|
|
||||||
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
|
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
|
||||||
|
|
||||||
|
@ -8070,6 +8072,9 @@ namespace ts {
|
||||||
// we remove type string.
|
// we remove type string.
|
||||||
function getAssignmentReducedType(declaredType: UnionType, assignedType: Type) {
|
function getAssignmentReducedType(declaredType: UnionType, assignedType: Type) {
|
||||||
if (declaredType !== assignedType) {
|
if (declaredType !== assignedType) {
|
||||||
|
if (assignedType.flags & TypeFlags.Never) {
|
||||||
|
return assignedType;
|
||||||
|
}
|
||||||
const reducedType = filterType(declaredType, t => typeMaybeAssignableTo(assignedType, t));
|
const reducedType = filterType(declaredType, t => typeMaybeAssignableTo(assignedType, t));
|
||||||
if (!(reducedType.flags & TypeFlags.Never)) {
|
if (!(reducedType.flags & TypeFlags.Never)) {
|
||||||
return reducedType;
|
return reducedType;
|
||||||
|
@ -8445,12 +8450,13 @@ namespace ts {
|
||||||
// attempt to narrow the antecedent type. If that produces the never type, and if
|
// attempt to narrow the antecedent type. If that produces the never type, and if
|
||||||
// the antecedent type is incomplete (i.e. a transient type in a loop), then we
|
// the antecedent type is incomplete (i.e. a transient type in a loop), then we
|
||||||
// take the type guard as an indication that control *could* reach here once we
|
// take the type guard as an indication that control *could* reach here once we
|
||||||
// have the complete type. We proceed by reverting to the declared type and then
|
// have the complete type. We proceed by switching to the silent never type which
|
||||||
// narrow that.
|
// doesn't report errors when operators are applied to it. Note that this is the
|
||||||
|
// *only* place a silent never type is ever generated.
|
||||||
const assumeTrue = (flow.flags & FlowFlags.TrueCondition) !== 0;
|
const assumeTrue = (flow.flags & FlowFlags.TrueCondition) !== 0;
|
||||||
type = narrowType(type, flow.expression, assumeTrue);
|
type = narrowType(type, flow.expression, assumeTrue);
|
||||||
if (type.flags & TypeFlags.Never && isIncomplete(flowType)) {
|
if (type.flags & TypeFlags.Never && isIncomplete(flowType)) {
|
||||||
type = narrowType(declaredType, flow.expression, assumeTrue);
|
type = silentNeverType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return createFlowType(type, isIncomplete(flowType));
|
return createFlowType(type, isIncomplete(flowType));
|
||||||
|
@ -10889,7 +10895,7 @@ namespace ts {
|
||||||
|
|
||||||
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
|
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
|
||||||
const type = checkNonNullExpression(left);
|
const type = checkNonNullExpression(left);
|
||||||
if (isTypeAny(type)) {
|
if (isTypeAny(type) || type === silentNeverType) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11036,8 +11042,8 @@ namespace ts {
|
||||||
const objectType = getApparentType(checkNonNullExpression(node.expression));
|
const objectType = getApparentType(checkNonNullExpression(node.expression));
|
||||||
const indexType = node.argumentExpression ? checkExpression(node.argumentExpression) : unknownType;
|
const indexType = node.argumentExpression ? checkExpression(node.argumentExpression) : unknownType;
|
||||||
|
|
||||||
if (objectType === unknownType) {
|
if (objectType === unknownType || objectType === silentNeverType) {
|
||||||
return unknownType;
|
return objectType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isConstEnum = isConstEnumObjectType(objectType);
|
const isConstEnum = isConstEnumObjectType(objectType);
|
||||||
|
@ -12087,6 +12093,9 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
const funcType = checkNonNullExpression(node.expression);
|
const funcType = checkNonNullExpression(node.expression);
|
||||||
|
if (funcType === silentNeverType) {
|
||||||
|
return silentNeverSignature;
|
||||||
|
}
|
||||||
const apparentType = getApparentType(funcType);
|
const apparentType = getApparentType(funcType);
|
||||||
|
|
||||||
if (apparentType === unknownType) {
|
if (apparentType === unknownType) {
|
||||||
|
@ -12159,6 +12168,9 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
let expressionType = checkNonNullExpression(node.expression);
|
let expressionType = checkNonNullExpression(node.expression);
|
||||||
|
if (expressionType === silentNeverType) {
|
||||||
|
return silentNeverSignature;
|
||||||
|
}
|
||||||
|
|
||||||
// If expressionType's apparent type(section 3.8.1) is an object type with one or
|
// If expressionType's apparent type(section 3.8.1) is an object type with one or
|
||||||
// more construct signatures, the expression is processed in the same manner as a
|
// more construct signatures, the expression is processed in the same manner as a
|
||||||
|
@ -13024,6 +13036,9 @@ namespace ts {
|
||||||
|
|
||||||
function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type {
|
function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type {
|
||||||
const operandType = checkExpression(node.operand);
|
const operandType = checkExpression(node.operand);
|
||||||
|
if (operandType === silentNeverType) {
|
||||||
|
return silentNeverType;
|
||||||
|
}
|
||||||
if (node.operator === SyntaxKind.MinusToken && node.operand.kind === SyntaxKind.NumericLiteral) {
|
if (node.operator === SyntaxKind.MinusToken && node.operand.kind === SyntaxKind.NumericLiteral) {
|
||||||
return getLiteralTypeForText(TypeFlags.NumberLiteral, "" + -(<LiteralExpression>node.operand).text);
|
return getLiteralTypeForText(TypeFlags.NumberLiteral, "" + -(<LiteralExpression>node.operand).text);
|
||||||
}
|
}
|
||||||
|
@ -13057,6 +13072,9 @@ namespace ts {
|
||||||
|
|
||||||
function checkPostfixUnaryExpression(node: PostfixUnaryExpression): Type {
|
function checkPostfixUnaryExpression(node: PostfixUnaryExpression): Type {
|
||||||
const operandType = checkExpression(node.operand);
|
const operandType = checkExpression(node.operand);
|
||||||
|
if (operandType === silentNeverType) {
|
||||||
|
return silentNeverType;
|
||||||
|
}
|
||||||
const ok = checkArithmeticOperandType(node.operand, getNonNullableType(operandType),
|
const ok = checkArithmeticOperandType(node.operand, getNonNullableType(operandType),
|
||||||
Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type);
|
Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
|
@ -13121,6 +13139,9 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkInstanceOfExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type {
|
function checkInstanceOfExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type {
|
||||||
|
if (leftType === silentNeverType || rightType === silentNeverType) {
|
||||||
|
return silentNeverType;
|
||||||
|
}
|
||||||
// TypeScript 1.0 spec (April 2014): 4.15.4
|
// TypeScript 1.0 spec (April 2014): 4.15.4
|
||||||
// The instanceof operator requires the left operand to be of type Any, an object type, or a type parameter type,
|
// The instanceof operator requires the left operand to be of type Any, an object type, or a type parameter type,
|
||||||
// and the right operand to be of type Any or a subtype of the 'Function' interface type.
|
// and the right operand to be of type Any or a subtype of the 'Function' interface type.
|
||||||
|
@ -13137,6 +13158,9 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkInExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type {
|
function checkInExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type {
|
||||||
|
if (leftType === silentNeverType || rightType === silentNeverType) {
|
||||||
|
return silentNeverType;
|
||||||
|
}
|
||||||
// TypeScript 1.0 spec (April 2014): 4.15.5
|
// TypeScript 1.0 spec (April 2014): 4.15.5
|
||||||
// The in operator requires the left operand to be of type Any, the String primitive type, or the Number primitive type,
|
// The in operator requires the left operand to be of type Any, the String primitive type, or the Number primitive type,
|
||||||
// and the right operand to be of type Any, an object type, or a type parameter type.
|
// and the right operand to be of type Any, an object type, or a type parameter type.
|
||||||
|
@ -13401,6 +13425,9 @@ namespace ts {
|
||||||
case SyntaxKind.CaretEqualsToken:
|
case SyntaxKind.CaretEqualsToken:
|
||||||
case SyntaxKind.AmpersandToken:
|
case SyntaxKind.AmpersandToken:
|
||||||
case SyntaxKind.AmpersandEqualsToken:
|
case SyntaxKind.AmpersandEqualsToken:
|
||||||
|
if (leftType === silentNeverType || rightType === silentNeverType) {
|
||||||
|
return silentNeverType;
|
||||||
|
}
|
||||||
// TypeScript 1.0 spec (April 2014): 4.19.1
|
// TypeScript 1.0 spec (April 2014): 4.19.1
|
||||||
// These operators require their operands to be of type Any, the Number primitive type,
|
// These operators require their operands to be of type Any, the Number primitive type,
|
||||||
// or an enum type. Operands of an enum type are treated
|
// or an enum type. Operands of an enum type are treated
|
||||||
|
@ -13433,6 +13460,9 @@ namespace ts {
|
||||||
return numberType;
|
return numberType;
|
||||||
case SyntaxKind.PlusToken:
|
case SyntaxKind.PlusToken:
|
||||||
case SyntaxKind.PlusEqualsToken:
|
case SyntaxKind.PlusEqualsToken:
|
||||||
|
if (leftType === silentNeverType || rightType === silentNeverType) {
|
||||||
|
return silentNeverType;
|
||||||
|
}
|
||||||
// TypeScript 1.0 spec (April 2014): 4.19.2
|
// TypeScript 1.0 spec (April 2014): 4.19.2
|
||||||
// The binary + operator requires both operands to be of the Number primitive type or an enum type,
|
// The binary + operator requires both operands to be of the Number primitive type or an enum type,
|
||||||
// or at least one of the operands to be of type Any or the String primitive type.
|
// or at least one of the operands to be of type Any or the String primitive type.
|
||||||
|
|
Loading…
Reference in a new issue