Skip to content

Commit 111ca92

Browse files
Jesse Trinitysandersn
Jesse Trinity
andauthored
Fix parser regression for bad related diagnostic on missing matching brackets (microsoft#44158)
* Revert "Revert microsoft#43460 and microsoft#40884 (microsoft#44175)" This reverts commit 5770434. * fix missing opening brace match error * refactor parseExpectedMatchingBrackets * use getNodePos * accept baselines * delete mistakenly added files * Revert getNodePos addition Co-authored-by: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com>
1 parent 8c060ee commit 111ca92

File tree

60 files changed

+299
-353
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+299
-353
lines changed

src/compiler/diagnosticMessages.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"category": "Error",
1616
"code": 1006
1717
},
18-
"The parser expected to find a '}' to match the '{' token here.": {
18+
"The parser expected to find a '{1}' to match the '{0}' token here.": {
1919
"category": "Error",
2020
"code": 1007
2121
},

src/compiler/parser.ts

+50-44
Original file line numberDiff line numberDiff line change
@@ -1434,24 +1434,27 @@ namespace ts {
14341434
return inContext(NodeFlags.AwaitContext);
14351435
}
14361436

1437-
function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): void {
1438-
parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), message, arg0);
1437+
function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined {
1438+
return parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), message, arg0);
14391439
}
14401440

1441-
function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): void {
1441+
function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined {
14421442
// Don't report another error if it would just be at the same position as the last error.
14431443
const lastError = lastOrUndefined(parseDiagnostics);
1444+
let result: DiagnosticWithDetachedLocation | undefined;
14441445
if (!lastError || start !== lastError.start) {
1445-
parseDiagnostics.push(createDetachedDiagnostic(fileName, start, length, message, arg0));
1446+
result = createDetachedDiagnostic(fileName, start, length, message, arg0);
1447+
parseDiagnostics.push(result);
14461448
}
14471449

14481450
// Mark that we've encountered an error. We'll set an appropriate bit on the next
14491451
// node we finish so that it can't be reused incrementally.
14501452
parseErrorBeforeNextFinishedNode = true;
1453+
return result;
14511454
}
14521455

1453-
function parseErrorAt(start: number, end: number, message: DiagnosticMessage, arg0?: any): void {
1454-
parseErrorAtPosition(start, end - start, message, arg0);
1456+
function parseErrorAt(start: number, end: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined {
1457+
return parseErrorAtPosition(start, end - start, message, arg0);
14551458
}
14561459

14571460
function parseErrorAtRange(range: TextRange, message: DiagnosticMessage, arg0?: any): void {
@@ -1779,6 +1782,23 @@ namespace ts {
17791782
return false;
17801783
}
17811784

1785+
function parseExpectedMatchingBrackets(openKind: SyntaxKind, closeKind: SyntaxKind, openParsed: boolean, openPosition: number) {
1786+
if (token() === closeKind) {
1787+
nextToken();
1788+
return;
1789+
}
1790+
const lastError = parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(closeKind));
1791+
if (!openParsed) {
1792+
return;
1793+
}
1794+
if (lastError) {
1795+
addRelatedInfo(
1796+
lastError,
1797+
createDetachedDiagnostic(fileName, openPosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, tokenToString(openKind), tokenToString(closeKind))
1798+
);
1799+
}
1800+
}
1801+
17821802
function parseOptional(t: SyntaxKind): boolean {
17831803
if (token() === t) {
17841804
nextToken();
@@ -3739,7 +3759,7 @@ namespace ts {
37393759
if (lastError && lastError.code === Diagnostics._0_expected.code) {
37403760
addRelatedInfo(
37413761
lastError,
3742-
createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_to_match_the_token_here)
3762+
createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}")
37433763
);
37443764
}
37453765
}
@@ -5772,10 +5792,11 @@ namespace ts {
57725792

57735793
function parseArrayLiteralExpression(): ArrayLiteralExpression {
57745794
const pos = getNodePos();
5775-
parseExpected(SyntaxKind.OpenBracketToken);
5795+
const openBracketPosition = scanner.getTokenPos();
5796+
const openBracketParsed = parseExpected(SyntaxKind.OpenBracketToken);
57765797
const multiLine = scanner.hasPrecedingLineBreak();
57775798
const elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement);
5778-
parseExpected(SyntaxKind.CloseBracketToken);
5799+
parseExpectedMatchingBrackets(SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, openBracketParsed, openBracketPosition);
57795800
return finishNode(factory.createArrayLiteralExpression(elements, multiLine), pos);
57805801
}
57815802

@@ -5841,18 +5862,10 @@ namespace ts {
58415862
function parseObjectLiteralExpression(): ObjectLiteralExpression {
58425863
const pos = getNodePos();
58435864
const openBracePosition = scanner.getTokenPos();
5844-
parseExpected(SyntaxKind.OpenBraceToken);
5865+
const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken);
58455866
const multiLine = scanner.hasPrecedingLineBreak();
58465867
const properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true);
5847-
if (!parseExpected(SyntaxKind.CloseBraceToken)) {
5848-
const lastError = lastOrUndefined(parseDiagnostics);
5849-
if (lastError && lastError.code === Diagnostics._0_expected.code) {
5850-
addRelatedInfo(
5851-
lastError,
5852-
createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_to_match_the_token_here)
5853-
);
5854-
}
5855-
}
5868+
parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition);
58565869
return finishNode(factory.createObjectLiteralExpression(properties, multiLine), pos);
58575870
}
58585871

@@ -5916,18 +5929,11 @@ namespace ts {
59165929
const pos = getNodePos();
59175930
const hasJSDoc = hasPrecedingJSDocComment();
59185931
const openBracePosition = scanner.getTokenPos();
5919-
if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) {
5932+
const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage);
5933+
if (openBraceParsed || ignoreMissingOpenBrace) {
59205934
const multiLine = scanner.hasPrecedingLineBreak();
59215935
const statements = parseList(ParsingContext.BlockStatements, parseStatement);
5922-
if (!parseExpected(SyntaxKind.CloseBraceToken)) {
5923-
const lastError = lastOrUndefined(parseDiagnostics);
5924-
if (lastError && lastError.code === Diagnostics._0_expected.code) {
5925-
addRelatedInfo(
5926-
lastError,
5927-
createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_to_match_the_token_here)
5928-
);
5929-
}
5930-
}
5936+
parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition);
59315937
const result = withJSDoc(finishNode(factory.createBlock(statements, multiLine), pos), hasJSDoc);
59325938
if (token() === SyntaxKind.EqualsToken) {
59335939
parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected_This_follows_a_block_of_statements_so_if_you_intended_to_write_a_destructuring_assignment_you_might_need_to_wrap_the_the_whole_assignment_in_parentheses);
@@ -5983,9 +5989,10 @@ namespace ts {
59835989
const pos = getNodePos();
59845990
const hasJSDoc = hasPrecedingJSDocComment();
59855991
parseExpected(SyntaxKind.IfKeyword);
5986-
parseExpected(SyntaxKind.OpenParenToken);
5992+
const openParenPosition = scanner.getTokenPos();
5993+
const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);
59875994
const expression = allowInAnd(parseExpression);
5988-
parseExpected(SyntaxKind.CloseParenToken);
5995+
parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);
59895996
const thenStatement = parseStatement();
59905997
const elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined;
59915998
return withJSDoc(finishNode(factory.createIfStatement(expression, thenStatement, elseStatement), pos), hasJSDoc);
@@ -5997,9 +6004,10 @@ namespace ts {
59976004
parseExpected(SyntaxKind.DoKeyword);
59986005
const statement = parseStatement();
59996006
parseExpected(SyntaxKind.WhileKeyword);
6000-
parseExpected(SyntaxKind.OpenParenToken);
6007+
const openParenPosition = scanner.getTokenPos();
6008+
const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);
60016009
const expression = allowInAnd(parseExpression);
6002-
parseExpected(SyntaxKind.CloseParenToken);
6010+
parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);
60036011

60046012
// From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html
60056013
// 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in
@@ -6013,9 +6021,10 @@ namespace ts {
60136021
const pos = getNodePos();
60146022
const hasJSDoc = hasPrecedingJSDocComment();
60156023
parseExpected(SyntaxKind.WhileKeyword);
6016-
parseExpected(SyntaxKind.OpenParenToken);
6024+
const openParenPosition = scanner.getTokenPos();
6025+
const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);
60176026
const expression = allowInAnd(parseExpression);
6018-
parseExpected(SyntaxKind.CloseParenToken);
6027+
parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);
60196028
const statement = parseStatement();
60206029
return withJSDoc(finishNode(factory.createWhileStatement(expression, statement), pos), hasJSDoc);
60216030
}
@@ -6091,9 +6100,10 @@ namespace ts {
60916100
const pos = getNodePos();
60926101
const hasJSDoc = hasPrecedingJSDocComment();
60936102
parseExpected(SyntaxKind.WithKeyword);
6094-
parseExpected(SyntaxKind.OpenParenToken);
6103+
const openParenPosition = scanner.getTokenPos();
6104+
const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);
60956105
const expression = allowInAnd(parseExpression);
6096-
parseExpected(SyntaxKind.CloseParenToken);
6106+
parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);
60976107
const statement = doInsideOfContext(NodeFlags.InWithStatement, parseStatement);
60986108
return withJSDoc(finishNode(factory.createWithStatement(expression, statement), pos), hasJSDoc);
60996109
}
@@ -7398,7 +7408,7 @@ namespace ts {
73987408
if (lastError && lastError.code === Diagnostics._0_expected.code) {
73997409
addRelatedInfo(
74007410
lastError,
7401-
createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_to_match_the_token_here)
7411+
createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}")
74027412
);
74037413
}
74047414
}
@@ -8453,13 +8463,9 @@ namespace ts {
84538463
hasChildren = true;
84548464
if (child.kind === SyntaxKind.JSDocTypeTag) {
84558465
if (childTypeTag) {
8456-
parseErrorAtCurrentToken(Diagnostics.A_JSDoc_typedef_comment_may_not_contain_multiple_type_tags);
8457-
const lastError = lastOrUndefined(parseDiagnostics);
8466+
const lastError = parseErrorAtCurrentToken(Diagnostics.A_JSDoc_typedef_comment_may_not_contain_multiple_type_tags);
84588467
if (lastError) {
8459-
addRelatedInfo(
8460-
lastError,
8461-
createDetachedDiagnostic(fileName, 0, 0, Diagnostics.The_tag_was_first_specified_here)
8462-
);
8468+
addRelatedInfo(lastError, createDetachedDiagnostic(fileName, 0, 0, Diagnostics.The_tag_was_first_specified_here));
84638469
}
84648470
break;
84658471
}

tests/baselines/reference/constructorWithIncompleteTypeAnnotation.errors.txt

+1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(261,1): error TS
121121
if (retValue != 0 ^= {
122122
~~
123123
!!! error TS1005: ')' expected.
124+
!!! related TS1007 tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts:22:20: The parser expected to find a ')' to match the '(' token here.
124125
~
125126

126127

tests/baselines/reference/errorRecoveryWithDotFollowedByNamespaceKeyword.errors.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,4 @@ tests/cases/compiler/errorRecoveryWithDotFollowedByNamespaceKeyword.ts(9,2): err
1616
}
1717

1818
!!! error TS1005: '}' expected.
19-
!!! related TS1007 tests/cases/compiler/errorRecoveryWithDotFollowedByNamespaceKeyword.ts:3:19: The parser expected to find a '}' to match the '{' token here.
20-
!!! related TS1007 tests/cases/compiler/errorRecoveryWithDotFollowedByNamespaceKeyword.ts:2:20: The parser expected to find a '}' to match the '{' token here.
19+
!!! related TS1007 tests/cases/compiler/errorRecoveryWithDotFollowedByNamespaceKeyword.ts:3:19: The parser expected to find a '}' to match the '{' token here.

tests/baselines/reference/jsonParserRecovery/JSX.errors.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,4 @@ JSX(15,10): error TS1005: '}' expected.
3333
</div>
3434
)
3535

36-
!!! error TS1005: '}' expected.
37-
!!! related TS1007 JSX:4:9: The parser expected to find a '}' to match the '{' token here.
36+
!!! error TS1005: '}' expected.

tests/baselines/reference/jsonParserRecovery/TypeScript_code.errors.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,4 @@ TypeScript code(1,22): error TS1005: '}' expected.
1616
~~~~
1717
!!! error TS1012: Unexpected token.
1818

19-
!!! error TS1005: '}' expected.
20-
!!! related TS1007 TypeScript code:1:18: The parser expected to find a '}' to match the '{' token here.
19+
!!! error TS1005: '}' expected.

tests/baselines/reference/jsonParserRecovery/trailing_identifier.errors.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,4 @@ trailing identifier(1,8): error TS1005: '}' expected.
77
~~~~
88
!!! error TS1012: Unexpected token.
99

10-
!!! error TS1005: '}' expected.
11-
!!! related TS1007 trailing identifier:1:4: The parser expected to find a '}' to match the '{' token here.
10+
!!! error TS1005: '}' expected.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
tests/cases/compiler/missingCloseBracketInArray.ts(1,48): error TS1005: ']' expected.
2+
3+
4+
==== tests/cases/compiler/missingCloseBracketInArray.ts (1 errors) ====
5+
var alphas:string[] = alphas = ["1","2","3","4"
6+
7+
!!! error TS1005: ']' expected.
8+
!!! related TS1007 tests/cases/compiler/missingCloseBracketInArray.ts:1:32: The parser expected to find a ']' to match the '[' token here.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//// [missingCloseBracketInArray.ts]
2+
var alphas:string[] = alphas = ["1","2","3","4"
3+
4+
//// [missingCloseBracketInArray.js]
5+
var alphas = alphas = ["1", "2", "3", "4"];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
=== tests/cases/compiler/missingCloseBracketInArray.ts ===
2+
var alphas:string[] = alphas = ["1","2","3","4"
3+
>alphas : Symbol(alphas, Decl(missingCloseBracketInArray.ts, 0, 3))
4+
>alphas : Symbol(alphas, Decl(missingCloseBracketInArray.ts, 0, 3))
5+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/missingCloseBracketInArray.ts ===
2+
var alphas:string[] = alphas = ["1","2","3","4"
3+
>alphas : string[]
4+
>alphas = ["1","2","3","4" : string[]
5+
>alphas : string[]
6+
>["1","2","3","4" : string[]
7+
>"1" : "1"
8+
>"2" : "2"
9+
>"3" : "3"
10+
>"4" : "4"
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
tests/cases/compiler/missingCloseParenStatements.ts(2,26): error TS1005: ')' expected.
2+
tests/cases/compiler/missingCloseParenStatements.ts(4,5): error TS1005: ')' expected.
3+
tests/cases/compiler/missingCloseParenStatements.ts(8,39): error TS1005: ')' expected.
4+
tests/cases/compiler/missingCloseParenStatements.ts(11,35): error TS1005: ')' expected.
5+
6+
7+
==== tests/cases/compiler/missingCloseParenStatements.ts (4 errors) ====
8+
var a1, a2, a3 = 0;
9+
if ( a1 && (a2 + a3 > 0) {
10+
~
11+
!!! error TS1005: ')' expected.
12+
!!! related TS1007 tests/cases/compiler/missingCloseParenStatements.ts:2:4: The parser expected to find a ')' to match the '(' token here.
13+
while( (a2 > 0) && a1
14+
{
15+
~
16+
!!! error TS1005: ')' expected.
17+
!!! related TS1007 tests/cases/compiler/missingCloseParenStatements.ts:3:10: The parser expected to find a ')' to match the '(' token here.
18+
do {
19+
var i = i + 1;
20+
a1 = a1 + i;
21+
with ((a2 + a3 > 0) && a1 {
22+
~
23+
!!! error TS1005: ')' expected.
24+
!!! related TS1007 tests/cases/compiler/missingCloseParenStatements.ts:8:18: The parser expected to find a ')' to match the '(' token here.
25+
console.log(x);
26+
}
27+
} while (i < 5 && (a1 > 5);
28+
~
29+
!!! error TS1005: ')' expected.
30+
!!! related TS1007 tests/cases/compiler/missingCloseParenStatements.ts:11:17: The parser expected to find a ')' to match the '(' token here.
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [missingCloseParenStatements.ts]
2+
var a1, a2, a3 = 0;
3+
if ( a1 && (a2 + a3 > 0) {
4+
while( (a2 > 0) && a1
5+
{
6+
do {
7+
var i = i + 1;
8+
a1 = a1 + i;
9+
with ((a2 + a3 > 0) && a1 {
10+
console.log(x);
11+
}
12+
} while (i < 5 && (a1 > 5);
13+
}
14+
}
15+
16+
//// [missingCloseParenStatements.js]
17+
var a1, a2, a3 = 0;
18+
if (a1 && (a2 + a3 > 0)) {
19+
while ((a2 > 0) && a1) {
20+
do {
21+
var i = i + 1;
22+
a1 = a1 + i;
23+
with ((a2 + a3 > 0) && a1) {
24+
console.log(x);
25+
}
26+
} while (i < 5 && (a1 > 5));
27+
}
28+
}

0 commit comments

Comments
 (0)