mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-17 01:55:50 -06:00
Disallow comma operator when LHS is pure
This commit is contained in:
parent
b052d69dd8
commit
ab0a788fc8
@ -13209,6 +13209,82 @@ namespace ts {
|
||||
return sourceType;
|
||||
}
|
||||
|
||||
function isSideEffectFree(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.RegularExpressionLiteral:
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
case SyntaxKind.NullKeyword:
|
||||
case SyntaxKind.UndefinedKeyword:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return true;
|
||||
|
||||
case SyntaxKind.BinaryExpression:
|
||||
if (isAssignmentOperator((node as BinaryExpression).operatorToken.kind)) {
|
||||
return false;
|
||||
}
|
||||
return isSideEffectFree((node as BinaryExpression).left) &&
|
||||
isSideEffectFree((node as BinaryExpression).right);
|
||||
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
switch ((node as PrefixUnaryExpression).operator) {
|
||||
case SyntaxKind.ExclamationToken:
|
||||
case SyntaxKind.PlusToken:
|
||||
case SyntaxKind.MinusToken:
|
||||
case SyntaxKind.TildeToken:
|
||||
return isSideEffectFree((node as PrefixUnaryExpression).operand);
|
||||
}
|
||||
return false;
|
||||
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
case SyntaxKind.TypeOfExpression:
|
||||
case SyntaxKind.AsExpression:
|
||||
case SyntaxKind.NonNullExpression:
|
||||
// All the nodes which just have a .expression we should check
|
||||
return isSideEffectFree((node as ParenthesizedExpression).expression);
|
||||
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
return isSideEffectFree((node as ConditionalExpression).condition) &&
|
||||
isSideEffectFree((node as ConditionalExpression).whenTrue) &&
|
||||
isSideEffectFree((node as ConditionalExpression).whenFalse);
|
||||
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
// Note: negated forEach condition since we want to bail early to 'true',
|
||||
// in other words the callback is computing "Could have side effects?"
|
||||
return !forEach((node as ObjectLiteralExpression).properties, prop => {
|
||||
if (isComputedPropertyName(prop.name) && !isSideEffectFree((prop.name as ComputedPropertyName).expression)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (prop.kind) {
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
return false;
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
return !isSideEffectFree((prop as PropertyAssignment).initializer);
|
||||
default:
|
||||
Debug.fail('Unhandled object literal property kind ' + prop.kind);
|
||||
}
|
||||
});
|
||||
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
// See previous comment about negated callback values
|
||||
return !forEach((node as ArrayLiteralExpression).elements, elem => !isSideEffectFree(elem));
|
||||
|
||||
case SyntaxKind.VoidExpression:
|
||||
// Explicit opt-out case (listed here to avoid accidental duplication above): 'void x'
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isTypeEqualityComparableTo(source: Type, target: Type) {
|
||||
return (target.flags & TypeFlags.Nullable) !== 0 || isTypeComparableTo(source, target);
|
||||
}
|
||||
@ -13370,6 +13446,9 @@ namespace ts {
|
||||
checkAssignmentOperator(rightType);
|
||||
return getRegularTypeOfObjectLiteral(rightType);
|
||||
case SyntaxKind.CommaToken:
|
||||
if (isSideEffectFree(left) && !compilerOptions.allowUnreachableCode) {
|
||||
error(left, Diagnostics.Left_side_of_comma_operator_is_unused_and_has_no_side_effects);
|
||||
}
|
||||
return rightType;
|
||||
}
|
||||
|
||||
|
||||
@ -1955,6 +1955,10 @@
|
||||
"category": "Error",
|
||||
"code": 2692
|
||||
},
|
||||
"Left side of comma operator is unused and has no side effects.": {
|
||||
"category": "Error",
|
||||
"code": 2693
|
||||
},
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 4000
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
tests/cases/compiler/assignmentToParenthesizedExpression1.ts(2,1): error TS2364: Invalid left-hand side of assignment expression.
|
||||
tests/cases/compiler/assignmentToParenthesizedExpression1.ts(2,2): error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
|
||||
|
||||
==== tests/cases/compiler/assignmentToParenthesizedExpression1.ts (1 errors) ====
|
||||
==== tests/cases/compiler/assignmentToParenthesizedExpression1.ts (2 errors) ====
|
||||
var x;
|
||||
(1, x)=0;
|
||||
~~~~~~
|
||||
!!! error TS2364: Invalid left-hand side of assignment expression.
|
||||
!!! error TS2364: Invalid left-hand side of assignment expression.
|
||||
~
|
||||
!!! error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
33
tests/baselines/reference/commaOperator1.errors.txt
Normal file
33
tests/baselines/reference/commaOperator1.errors.txt
Normal file
@ -0,0 +1,33 @@
|
||||
tests/cases/compiler/commaOperator1.ts(1,11): error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
tests/cases/compiler/commaOperator1.ts(1,11): error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
tests/cases/compiler/commaOperator1.ts(1,11): error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
tests/cases/compiler/commaOperator1.ts(1,12): error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
tests/cases/compiler/commaOperator1.ts(1,12): error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
tests/cases/compiler/commaOperator1.ts(1,29): error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
tests/cases/compiler/commaOperator1.ts(4,12): error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
tests/cases/compiler/commaOperator1.ts(4,12): error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
|
||||
|
||||
==== tests/cases/compiler/commaOperator1.ts (8 errors) ====
|
||||
var v1 = ((1, 2, 3), 4, 5, (6, 7));
|
||||
~~~~~~~~~
|
||||
!!! error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
~
|
||||
!!! error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
~~~~
|
||||
!!! error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
~
|
||||
!!! error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
function f1() {
|
||||
var a = 1;
|
||||
return a, v1, a;
|
||||
~
|
||||
!!! error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
~~~~~
|
||||
!!! error TS2693: Left operand of comma operator may not be a side-effect free expression.
|
||||
}
|
||||
|
||||
45
tests/cases/compiler/commaOperatorLeftSideUnused.ts
Normal file
45
tests/cases/compiler/commaOperatorLeftSideUnused.ts
Normal file
@ -0,0 +1,45 @@
|
||||
var xx: any;
|
||||
|
||||
function fn() {
|
||||
let arr: any[] = [];
|
||||
switch(arr.length) {
|
||||
// Should error
|
||||
case 0, 1:
|
||||
return 'zero or one';
|
||||
default:
|
||||
return 'more than one';
|
||||
}
|
||||
}
|
||||
|
||||
// Should error
|
||||
let x = Math.pow((3, 5), 2);
|
||||
|
||||
// Should error
|
||||
let a = [(3 + 4), ((1 + 1, 8) * 4)];
|
||||
|
||||
// Should be OK
|
||||
xx = x++, 2;
|
||||
xx = x = 3, 2;
|
||||
|
||||
// Should error
|
||||
xx = x = (3, 2);
|
||||
|
||||
// Error cases (object literals)
|
||||
xx = ({ x: 3 }, 14);
|
||||
xx = ({ y() { } }, 14);
|
||||
|
||||
// OK cases (object literals)
|
||||
xx = ({ m: Math.pow(2, 3) }), 14;
|
||||
xx = ({ ['foo'.substr(3)]: 5 }), 14;
|
||||
|
||||
// Error cases (array literals)
|
||||
xx = ([1, 2], 4);
|
||||
xx = ([], 4);
|
||||
xx = ([[]], 4);
|
||||
xx = ([{}], '');
|
||||
xx = ([false, true, (xx, xx)], 4);
|
||||
|
||||
// OK cases (array literals)
|
||||
xx = ([1, ''.substr(0)], '');
|
||||
xx = ([new Date()], '');
|
||||
xx = ([console.log], '');
|
||||
Loading…
x
Reference in New Issue
Block a user