Skip to content

Commit 89e675e

Browse files
committed
fix: range of ts2657 (jsx expr must have parent) and remove 2695 (LHS expr of comma has no side effects)
1 parent eb105ef commit 89e675e

File tree

7 files changed

+86
-79
lines changed

7 files changed

+86
-79
lines changed

src/compiler/checker.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28347,7 +28347,15 @@ namespace ts {
2834728347
}
2834828348
case SyntaxKind.CommaToken:
2834928349
if (!compilerOptions.allowUnreachableCode && isSideEffectFree(left) && !isEvalNode(right)) {
28350-
error(left, Diagnostics.Left_side_of_comma_operator_is_unused_and_has_no_side_effects);
28350+
const sf = getSourceFileOfNode(left);
28351+
const isInDiag2657 = sf.parseDiagnostics.some(diag => {
28352+
if (diag.code !== Diagnostics.JSX_expressions_must_have_one_parent_element.code) return false;
28353+
const start = diag.start;
28354+
const end = start + diag.length;
28355+
if (left.pos >= start && left.pos <= end) return true;
28356+
return false;
28357+
});
28358+
if (!isInDiag2657) error(left, Diagnostics.Left_side_of_comma_operator_is_unused_and_has_no_side_effects);
2835128359
}
2835228360
return rightType;
2835328361

src/compiler/parser.ts

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ namespace ts {
33
None = 0,
44
Yield = 1 << 0,
55
Await = 1 << 1,
6-
Type = 1 << 2,
6+
Type = 1 << 2,
77
IgnoreMissingOpenBrace = 1 << 4,
88
JSDoc = 1 << 5,
99
}
@@ -474,9 +474,9 @@ namespace ts {
474474
return visitNode(cbNode, (node as JSDocTag).tagName) ||
475475
((node as JSDocPropertyLikeTag).isNameFirst
476476
? visitNode(cbNode, (<JSDocPropertyLikeTag>node).name) ||
477-
visitNode(cbNode, (<JSDocPropertyLikeTag>node).typeExpression)
477+
visitNode(cbNode, (<JSDocPropertyLikeTag>node).typeExpression)
478478
: visitNode(cbNode, (<JSDocPropertyLikeTag>node).typeExpression) ||
479-
visitNode(cbNode, (<JSDocPropertyLikeTag>node).name));
479+
visitNode(cbNode, (<JSDocPropertyLikeTag>node).name));
480480
case SyntaxKind.JSDocAuthorTag:
481481
return visitNode(cbNode, (node as JSDocTag).tagName);
482482
case SyntaxKind.JSDocImplementsTag:
@@ -494,9 +494,9 @@ namespace ts {
494494
((node as JSDocTypedefTag).typeExpression &&
495495
(node as JSDocTypedefTag).typeExpression!.kind === SyntaxKind.JSDocTypeExpression
496496
? visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression) ||
497-
visitNode(cbNode, (<JSDocTypedefTag>node).fullName)
497+
visitNode(cbNode, (<JSDocTypedefTag>node).fullName)
498498
: visitNode(cbNode, (<JSDocTypedefTag>node).fullName) ||
499-
visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression));
499+
visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression));
500500
case SyntaxKind.JSDocCallbackTag:
501501
return visitNode(cbNode, (node as JSDocTag).tagName) ||
502502
visitNode(cbNode, (node as JSDocCallbackTag).fullName) ||
@@ -846,7 +846,7 @@ namespace ts {
846846
statement.expression = parseLiteralNode() as StringLiteral | NumericLiteral;
847847
break;
848848
}
849-
// falls through
849+
// falls through
850850
default:
851851
statement.expression = parseObjectLiteralExpression();
852852
break;
@@ -1394,8 +1394,8 @@ namespace ts {
13941394
const p = pos! >= 0 ? pos! : scanner.getStartPos();
13951395
return isNodeKind(kind) || kind === SyntaxKind.Unknown ? new NodeConstructor(kind, p, p) :
13961396
kind === SyntaxKind.Identifier ? new IdentifierConstructor(kind, p, p) :
1397-
kind === SyntaxKind.PrivateIdentifier ? new PrivateIdentifierConstructor(kind, p, p) :
1398-
new TokenConstructor(kind, p, p);
1397+
kind === SyntaxKind.PrivateIdentifier ? new PrivateIdentifierConstructor(kind, p, p) :
1398+
new TokenConstructor(kind, p, p);
13991399
}
14001400

14011401
function createNodeWithJSDoc(kind: SyntaxKind, pos?: number): Node {
@@ -1708,7 +1708,7 @@ namespace ts {
17081708
case SyntaxKind.DotToken: // Not an array literal member, but don't want to close the array (see `tests/cases/fourslash/completionsDotInArrayLiteralInObjectLiteral.ts`)
17091709
return true;
17101710
}
1711-
// falls through
1711+
// falls through
17121712
case ParsingContext.ArgumentExpressions:
17131713
return token() === SyntaxKind.DotDotDotToken || isStartOfExpression();
17141714
case ParsingContext.Parameters:
@@ -3153,7 +3153,7 @@ namespace ts {
31533153
case SyntaxKind.QuestionQuestionToken:
31543154
// If there is '??', consider that is prefix '?' in JSDoc type.
31553155
scanner.reScanQuestionToken();
3156-
// falls through
3156+
// falls through
31573157
case SyntaxKind.QuestionToken:
31583158
return parseJSDocUnknownOrNullableType();
31593159
case SyntaxKind.FunctionKeyword:
@@ -4250,7 +4250,7 @@ namespace ts {
42504250
if (isAwaitExpression()) {
42514251
return parseAwaitExpression();
42524252
}
4253-
// falls through
4253+
// falls through
42544254
default:
42554255
return parseUpdateExpression();
42564256
}
@@ -4284,8 +4284,8 @@ namespace ts {
42844284
if (sourceFile.languageVariant !== LanguageVariant.JSX) {
42854285
return false;
42864286
}
4287-
// We are in JSX context and the token is part of JSXElement.
4288-
// falls through
4287+
// We are in JSX context and the token is part of JSXElement.
4288+
// falls through
42894289
default:
42904290
return true;
42914291
}
@@ -4474,7 +4474,7 @@ namespace ts {
44744474
return finishNode(node);
44754475
}
44764476

4477-
function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement | JsxFragment {
4477+
function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number): JsxElement | JsxSelfClosingElement | JsxFragment {
44784478
const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext);
44794479
let result: JsxElement | JsxSelfClosingElement | JsxFragment;
44804480
if (opening.kind === SyntaxKind.JsxOpeningElement) {
@@ -4512,15 +4512,16 @@ namespace ts {
45124512
// Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios
45134513
// of one sort or another.
45144514
if (inExpressionContext && token() === SyntaxKind.LessThanToken) {
4515-
const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true));
4515+
const topBadPos = typeof topInvalidNodePosition === "undefined" ? result.pos : topInvalidNodePosition;
4516+
const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos));
45164517
if (invalidElement) {
4517-
parseErrorAtCurrentToken(Diagnostics.JSX_expressions_must_have_one_parent_element);
45184518
const badNode = <BinaryExpression>createNode(SyntaxKind.BinaryExpression, result.pos);
45194519
badNode.end = invalidElement.end;
45204520
badNode.left = result;
45214521
badNode.right = invalidElement;
45224522
badNode.operatorToken = createMissingNode(SyntaxKind.CommaToken, /*reportAtCurrentPosition*/ false);
45234523
badNode.operatorToken.pos = badNode.operatorToken.end = badNode.right.pos;
4524+
parseErrorAt(topBadPos, invalidElement.end, Diagnostics.JSX_expressions_must_have_one_parent_element);
45244525
return <JsxElement><Node>badNode;
45254526
}
45264527
}
@@ -5064,7 +5065,7 @@ namespace ts {
50645065
function parseArgumentOrArrayLiteralElement(): Expression {
50655066
return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() :
50665067
token() === SyntaxKind.CommaToken ? <Expression>createNode(SyntaxKind.OmittedExpression) :
5067-
parseAssignmentExpressionOrHigher();
5068+
parseAssignmentExpressionOrHigher();
50685069
}
50695070

50705071
function parseArgumentExpression(): Expression {
@@ -5175,9 +5176,9 @@ namespace ts {
51755176
const isAsync = hasModifierOfKind(node, SyntaxKind.AsyncKeyword) ? SignatureFlags.Await : SignatureFlags.None;
51765177
node.name =
51775178
isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) :
5178-
isGenerator ? doInYieldContext(parseOptionalIdentifier) :
5179-
isAsync ? doInAwaitContext(parseOptionalIdentifier) :
5180-
parseOptionalIdentifier();
5179+
isGenerator ? doInYieldContext(parseOptionalIdentifier) :
5180+
isAsync ? doInAwaitContext(parseOptionalIdentifier) :
5181+
parseOptionalIdentifier();
51815182

51825183
fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, node);
51835184
node.body = parseFunctionBlock(isGenerator | isAsync);
@@ -6720,8 +6721,8 @@ namespace ts {
67206721
// Try to use the first top-level import/export when available, then
67216722
// fall back to looking for an 'import.meta' somewhere in the tree if necessary.
67226723
sourceFile.externalModuleIndicator =
6723-
forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) ||
6724-
getImportMetaIfNecessary(sourceFile);
6724+
forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) ||
6725+
getImportMetaIfNecessary(sourceFile);
67256726
}
67266727

67276728
function isAnExternalModuleIndicatorNode(node: Node) {
@@ -7141,7 +7142,7 @@ namespace ts {
71417142
break;
71427143
}
71437144
scanner.setTextPos(scanner.getTextPos() - 1);
7144-
// falls through
7145+
// falls through
71457146
case SyntaxKind.EndOfFileToken:
71467147
// Done
71477148
break loop;
@@ -7184,8 +7185,8 @@ namespace ts {
71847185
indent += 1;
71857186
break;
71867187
}
7187-
// record the * as a comment
7188-
// falls through
7188+
// record the * as a comment
7189+
// falls through
71897190
default:
71907191
if (state !== JSDocState.SavingBackticks) {
71917192
state = JSDocState.SavingComments; // leading identifiers start recording as well
@@ -8499,7 +8500,7 @@ namespace ts {
84998500
return;
85008501
}
85018502
if (pragma.args) {
8502-
const argument: {[index: string]: string | {value: string, pos: number, end: number}} = {};
8503+
const argument: { [index: string]: string | { value: string, pos: number, end: number } } = {};
85038504
for (const arg of pragma.args) {
85048505
const matcher = getNamedArgRegEx(arg.name);
85058506
const matchResult = matcher.exec(text);
@@ -8556,11 +8557,11 @@ namespace ts {
85568557
return;
85578558
}
85588559

8559-
function getNamedPragmaArguments(pragma: PragmaDefinition, text: string | undefined): {[index: string]: string} | "fail" {
8560+
function getNamedPragmaArguments(pragma: PragmaDefinition, text: string | undefined): { [index: string]: string } | "fail" {
85608561
if (!text) return {};
85618562
if (!pragma.args) return {};
85628563
const args = text.split(/\s+/);
8563-
const argMap: {[index: string]: string} = {};
8564+
const argMap: { [index: string]: string } = {};
85648565
for (let i = 0; i < pragma.args.length; i++) {
85658566
const argument = pragma.args[i];
85668567
if (!args[i] && !argument.optional) {

tests/baselines/reference/jsxEsprimaFbTestSuite.errors.txt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,1): error TS2695: Left side of comma operator is unused and has no side effects.
1+
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(37,43): error TS2657: JSX expressions must have one parent element.
22
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,17): error TS1005: '{' expected.
3+
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,23): error TS1005: ';' expected.
34
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,23): error TS2304: Cannot find name 'right'.
4-
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,23): error TS2657: JSX expressions must have one parent element.
55
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,41): error TS1382: Unexpected token. Did you mean `{'>'}` or `&gt;`?
66
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,57): error TS1109: Expression expected.
77
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,58): error TS1109: Expression expected.
@@ -45,16 +45,18 @@ tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,58): error TS1109: Expr
4545
<div>@test content</div>;
4646

4747
<div><br />7x invalid-js-identifier</div>;
48+
49+
4850

4951
<LeftRight left=<a /> right=<b>monkeys /> gorillas</b> />;
50-
~~~~~~~~~~~~~~~~
51-
!!! error TS2695: Left side of comma operator is unused and has no side effects.
52+
~~~~~~~~~~~~~~~~~~~~~
53+
!!! error TS2657: JSX expressions must have one parent element.
5254
~
5355
!!! error TS1005: '{' expected.
5456
~~~~~
55-
!!! error TS2304: Cannot find name 'right'.
57+
!!! error TS1005: ';' expected.
5658
~~~~~
57-
!!! error TS2657: JSX expressions must have one parent element.
59+
!!! error TS2304: Cannot find name 'right'.
5860
~
5961
!!! error TS1382: Unexpected token. Did you mean `{'>'}` or `&gt;`?
6062
~

tests/baselines/reference/jsxInvalidEsprimaTestSuite.errors.txt

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,8 @@ tests/cases/conformance/jsx/16.tsx(1,2): error TS17008: JSX element 'a' has no c
3333
tests/cases/conformance/jsx/16.tsx(1,10): error TS1005: '</' expected.
3434
tests/cases/conformance/jsx/17.tsx(1,2): error TS17008: JSX element 'a' has no corresponding closing tag.
3535
tests/cases/conformance/jsx/17.tsx(1,10): error TS1005: '</' expected.
36-
tests/cases/conformance/jsx/18.tsx(1,9): error TS2695: Left side of comma operator is unused and has no side effects.
37-
tests/cases/conformance/jsx/18.tsx(1,37): error TS2657: JSX expressions must have one parent element.
38-
tests/cases/conformance/jsx/19.tsx(1,9): error TS2695: Left side of comma operator is unused and has no side effects.
39-
tests/cases/conformance/jsx/19.tsx(1,64): error TS2657: JSX expressions must have one parent element.
36+
tests/cases/conformance/jsx/18.tsx(1,8): error TS2657: JSX expressions must have one parent element.
37+
tests/cases/conformance/jsx/19.tsx(1,8): error TS2657: JSX expressions must have one parent element.
4038
tests/cases/conformance/jsx/2.tsx(1,3): error TS1003: Identifier expected.
4139
tests/cases/conformance/jsx/20.tsx(1,10): error TS1005: '}' expected.
4240
tests/cases/conformance/jsx/20.tsx(1,11): error TS1381: Unexpected token. Did you mean `{'}'}` or `&rbrace;`?
@@ -61,7 +59,7 @@ tests/cases/conformance/jsx/27.tsx(1,5): error TS1382: Unexpected token. Did you
6159
tests/cases/conformance/jsx/28.tsx(1,2): error TS17008: JSX element 'a' has no corresponding closing tag.
6260
tests/cases/conformance/jsx/28.tsx(1,6): error TS1005: '{' expected.
6361
tests/cases/conformance/jsx/28.tsx(2,1): error TS1005: '</' expected.
64-
tests/cases/conformance/jsx/29.tsx(1,1): error TS2695: Left side of comma operator is unused and has no side effects.
62+
tests/cases/conformance/jsx/29.tsx(1,1): error TS2657: JSX expressions must have one parent element.
6563
tests/cases/conformance/jsx/29.tsx(1,6): error TS1005: '{' expected.
6664
tests/cases/conformance/jsx/29.tsx(1,7): error TS1003: Identifier expected.
6765
tests/cases/conformance/jsx/29.tsx(2,1): error TS1005: '</' expected.
@@ -228,17 +226,13 @@ tests/cases/conformance/jsx/9.tsx(1,16): error TS1109: Expression expected.
228226
!!! error TS17008: JSX element 'a' has no corresponding closing tag.
229227

230228
!!! error TS1005: '</' expected.
231-
==== tests/cases/conformance/jsx/18.tsx (2 errors) ====
229+
==== tests/cases/conformance/jsx/18.tsx (1 errors) ====
232230
var x = <div>one</div><div>two</div>;;
233-
~~~~~~~~~~~~~~
234-
!!! error TS2695: Left side of comma operator is unused and has no side effects.
235-
~
231+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
236232
!!! error TS2657: JSX expressions must have one parent element.
237-
==== tests/cases/conformance/jsx/19.tsx (2 errors) ====
233+
==== tests/cases/conformance/jsx/19.tsx (1 errors) ====
238234
var x = <div>one</div> /* intervening comment */ <div>two</div>;;
239-
~~~~~~~~~~~~~~
240-
!!! error TS2695: Left side of comma operator is unused and has no side effects.
241-
~
235+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
242236
!!! error TS2657: JSX expressions must have one parent element.
243237
==== tests/cases/conformance/jsx/20.tsx (2 errors) ====
244238
<a>{"str";}</a>;
@@ -313,14 +307,15 @@ tests/cases/conformance/jsx/9.tsx(1,16): error TS1109: Expression expected.
313307
!!! error TS1005: '</' expected.
314308
==== tests/cases/conformance/jsx/29.tsx (4 errors) ====
315309
<a b=<}>;
316-
~~~~~
317-
!!! error TS2695: Left side of comma operator is unused and has no side effects.
310+
~~~~~~~~~
318311
~
319312
!!! error TS1005: '{' expected.
320313
~
321314
!!! error TS1003: Identifier expected.
322315

323316

317+
!!! error TS2657: JSX expressions must have one parent element.
318+
324319
!!! error TS1005: '</' expected.
325320
==== tests/cases/conformance/jsx/30.tsx (1 errors) ====
326321
<a>}</a>;
Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
1-
tests/cases/conformance/jsx/file1.tsx(3,1): error TS2695: Left side of comma operator is unused and has no side effects.
2-
tests/cases/conformance/jsx/file1.tsx(5,1): error TS2657: JSX expressions must have one parent element.
3-
tests/cases/conformance/jsx/file2.tsx(1,9): error TS2695: Left side of comma operator is unused and has no side effects.
4-
tests/cases/conformance/jsx/file2.tsx(2,1): error TS2657: JSX expressions must have one parent element.
1+
tests/cases/conformance/jsx/file1.tsx(1,48): error TS2657: JSX expressions must have one parent element.
2+
tests/cases/conformance/jsx/file2.tsx(1,8): error TS2657: JSX expressions must have one parent element.
53

64

7-
==== tests/cases/conformance/jsx/file1.tsx (2 errors) ====
5+
==== tests/cases/conformance/jsx/file1.tsx (1 errors) ====
86
declare namespace JSX { interface Element { } }
7+
8+
99

1010
<div></div>
1111
~~~~~~~~~~~
12-
!!! error TS2695: Left side of comma operator is unused and has no side effects.
1312
<div></div>
14-
15-
13+
~~~~~~~~~~~
1614
!!! error TS2657: JSX expressions must have one parent element.
17-
==== tests/cases/conformance/jsx/file2.tsx (2 errors) ====
18-
var x = <div></div><div></div>
19-
~~~~~~~~~~~
20-
!!! error TS2695: Left side of comma operator is unused and has no side effects.
21-
2215

23-
!!! error TS2657: JSX expressions must have one parent element.
16+
==== tests/cases/conformance/jsx/file2.tsx (1 errors) ====
17+
var x = <div></div><div></div>
18+
~~~~~~~~~~~~~~~~~~~~~~~
19+
!!! error TS2657: JSX expressions must have one parent element.
20+

0 commit comments

Comments
 (0)