Skip to content

Commit 9f33bd9

Browse files
committed
check both prefix + postfix unary expressions
1 parent 9c2ed8f commit 9f33bd9

File tree

2 files changed

+29
-14
lines changed

2 files changed

+29
-14
lines changed

src/compiler/checker.ts

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13097,6 +13097,11 @@ namespace ts {
1309713097
isUnitType(type);
1309813098
}
1309913099

13100+
function isStringOrNumericLiteralType(type: Type): boolean {
13101+
return type.flags & TypeFlags.Union ? every((<UnionType>type).types, t => !!(t.flags & TypeFlags.StringOrNumberLiteral && !(t.flags & (TypeFlags.EnumLike | TypeFlags.Intrinsic)))) :
13102+
!!(type.flags & TypeFlags.StringOrNumberLiteral) && !(type.flags & (TypeFlags.EnumLike | TypeFlags.Intrinsic))
13103+
}
13104+
1310013105
function getBaseTypeOfLiteralType(type: Type): Type {
1310113106
return type.flags & TypeFlags.EnumLiteral ? getBaseTypeOfEnumLiteralType(<LiteralType>type) :
1310213107
type.flags & TypeFlags.StringLiteral ? stringType :
@@ -21584,17 +21589,7 @@ namespace ts {
2158421589
}
2158521590

2158621591
function checkPostfixUnaryExpression(node: PostfixUnaryExpression): Type {
21587-
let operandType: Type;
21588-
const symbol = isEntityNameExpression(node.operand) ? isPropertyAccessEntityNameExpression(node.operand) ?
21589-
getSymbolAtLocation((<PropertyAccessExpression>node.operand).name) : getResolvedSymbol(node.operand as Identifier) : undefined;
21590-
if (symbol && !(getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const)) {
21591-
operandType = getTypeOfSymbol(symbol);
21592-
if (isLiteralType(operandType) && !(operandType.flags & (TypeFlags.EnumLike | TypeFlags.BooleanLike | TypeFlags.Undefined))) {
21593-
error(node.operand, Diagnostics.The_literal_type_0_cannot_be_modified, typeToString(operandType));
21594-
}
21595-
}
21596-
operandType = checkExpression(node.operand);
21597-
21592+
const operandType = checkExpression(node.operand);
2159821593
if (operandType === silentNeverType) {
2159921594
return silentNeverType;
2160021595
}
@@ -21619,6 +21614,21 @@ namespace ts {
2161921614
return numberType;
2162021615
}
2162121616

21617+
function checkUnaryExpression(node: PrefixUnaryExpression | PostfixUnaryExpression): Type {
21618+
const symbol = isEntityNameExpression(node.operand) ? isPropertyAccessEntityNameExpression(node.operand) ?
21619+
getSymbolAtLocation((<PropertyAccessExpression>node.operand).name) : getResolvedSymbol(node.operand as Identifier) : undefined;
21620+
if (symbol && isUnaryAssignmentOperator(node.operator) && !(getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const)) {
21621+
const operandType = getTypeOfSymbol(symbol);
21622+
if (isStringOrNumericLiteralType(operandType)) {
21623+
error(node.operand, Diagnostics.The_literal_type_0_cannot_be_modified, typeToString(operandType));
21624+
}
21625+
}
21626+
if (node.kind == SyntaxKind.PrefixUnaryExpression) {
21627+
return checkPrefixUnaryExpression(node)
21628+
}
21629+
return checkPostfixUnaryExpression(node)
21630+
}
21631+
2162221632
// Return true if type might be of the given kind. A union or intersection type might be of a given
2162321633
// kind if at least one constituent type is of the given kind.
2162421634
function maybeTypeOfKind(type: Type, kind: TypeFlags): boolean {
@@ -21967,7 +21977,7 @@ namespace ts {
2196721977
getSymbolAtLocation((<PropertyAccessExpression>left).name) : getResolvedSymbol(left as Identifier) : undefined;
2196821978
if (symbol && isCompoundAssignmentOperator(operator) && !(getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const)) {
2196921979
leftType = getTypeOfSymbol(getResolvedSymbol(left as Identifier));
21970-
if (isLiteralType(leftType) && !(leftType.flags & (TypeFlags.EnumLike | TypeFlags.BooleanLike | TypeFlags.Undefined))) {
21980+
if (isStringOrNumericLiteralType(leftType)) {
2197121981
error(left, Diagnostics.The_literal_type_0_cannot_be_modified, typeToString(leftType));
2197221982
}
2197321983
}
@@ -22658,9 +22668,8 @@ namespace ts {
2265822668
case SyntaxKind.AwaitExpression:
2265922669
return checkAwaitExpression(<AwaitExpression>node);
2266022670
case SyntaxKind.PrefixUnaryExpression:
22661-
return checkPrefixUnaryExpression(<PrefixUnaryExpression>node);
2266222671
case SyntaxKind.PostfixUnaryExpression:
22663-
return checkPostfixUnaryExpression(<PostfixUnaryExpression>node);
22672+
return checkUnaryExpression(<PrefixUnaryExpression | PostfixUnaryExpression>node);
2266422673
case SyntaxKind.BinaryExpression:
2266522674
return checkBinaryExpression(<BinaryExpression>node, checkMode);
2266622675
case SyntaxKind.ConditionalExpression:

src/compiler/utilities.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3789,6 +3789,12 @@ namespace ts {
37893789
|| token === SyntaxKind.GreaterThanGreaterThanEqualsToken;
37903790
}
37913791

3792+
export function isUnaryAssignmentOperator(token: SyntaxKind): boolean {
3793+
return token === SyntaxKind.PlusPlusToken
3794+
|| token === SyntaxKind.MinusMinusToken
3795+
3796+
}
3797+
37923798
export function isAssignmentOperator(token: SyntaxKind): boolean {
37933799
return token >= SyntaxKind.FirstAssignment && token <= SyntaxKind.LastAssignment;
37943800
}

0 commit comments

Comments
 (0)