Skip to content

Commit 449f4a4

Browse files
Have better error recovery for whne a user uses semicolons instead of commas to delimit an object literal.
1 parent 369f784 commit 449f4a4

26 files changed

+177
-31
lines changed

src/compiler/parser.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -1878,7 +1878,7 @@ module ts {
18781878
}
18791879

18801880
// Parses a comma-delimited list of elements
1881-
function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T): NodeArray<T> {
1881+
function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimeter?: boolean): NodeArray<T> {
18821882
var saveParsingContext = parsingContext;
18831883
parsingContext |= 1 << kind;
18841884
var result = <NodeArray<T>>[];
@@ -1892,11 +1892,24 @@ module ts {
18921892
if (parseOptional(SyntaxKind.CommaToken)) {
18931893
continue;
18941894
}
1895+
18951896
commaStart = -1; // Back to the state where the last token was not a comma
18961897
if (isListTerminator(kind)) {
18971898
break;
18981899
}
1900+
1901+
// We didn't get a comma, and the list wasn't terminated, explicitly parse
1902+
// out a comma so we give a good error message.
18991903
parseExpected(SyntaxKind.CommaToken);
1904+
1905+
// If the token was a semicolon, and the caller allows that, then skip it and
1906+
// continue. This ensures we get back on track and don't result in tons of
1907+
// parse errors. For example, this can happen when people do things like use
1908+
// a semicolon to delimit object literal members. Note: we'll have already
1909+
// reported an error when we called parseExpected above.
1910+
if (considerSemicolonAsDelimeter && token === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) {
1911+
nextToken();
1912+
}
19001913
continue;
19011914
}
19021915

@@ -3598,7 +3611,7 @@ module ts {
35983611
node.flags |= NodeFlags.MultiLine;
35993612
}
36003613

3601-
node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement);
3614+
node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimeter:*/ true);
36023615
parseExpected(SyntaxKind.CloseBraceToken);
36033616
return finishNode(node);
36043617
}

tests/baselines/reference/fatarrowfunctionsErrors.errors.txt

+1-7
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ tests/cases/compiler/fatarrowfunctionsErrors.ts(2,1): error TS2304: Cannot find
33
tests/cases/compiler/fatarrowfunctionsErrors.ts(2,8): error TS1005: ',' expected.
44
tests/cases/compiler/fatarrowfunctionsErrors.ts(2,18): error TS1005: ':' expected.
55
tests/cases/compiler/fatarrowfunctionsErrors.ts(2,19): error TS1005: ',' expected.
6-
tests/cases/compiler/fatarrowfunctionsErrors.ts(2,20): error TS1128: Declaration or statement expected.
7-
tests/cases/compiler/fatarrowfunctionsErrors.ts(2,21): error TS1128: Declaration or statement expected.
86
tests/cases/compiler/fatarrowfunctionsErrors.ts(3,1): error TS2304: Cannot find name 'foo'.
97
tests/cases/compiler/fatarrowfunctionsErrors.ts(4,1): error TS2304: Cannot find name 'foo'.
108
tests/cases/compiler/fatarrowfunctionsErrors.ts(5,9): error TS2304: Cannot find name 'x'.
@@ -18,7 +16,7 @@ tests/cases/compiler/fatarrowfunctionsErrors.ts(11,21): error TS1005: '=>' expec
1816
tests/cases/compiler/fatarrowfunctionsErrors.ts(12,23): error TS1005: '=>' expected.
1917

2018

21-
==== tests/cases/compiler/fatarrowfunctionsErrors.ts (18 errors) ====
19+
==== tests/cases/compiler/fatarrowfunctionsErrors.ts (16 errors) ====
2220
foo((...Far:any[])=>{return 0;})
2321
~~~
2422
!!! error TS2304: Cannot find name 'foo'.
@@ -31,10 +29,6 @@ tests/cases/compiler/fatarrowfunctionsErrors.ts(12,23): error TS1005: '=>' expec
3129
!!! error TS1005: ':' expected.
3230
~
3331
!!! error TS1005: ',' expected.
34-
~
35-
!!! error TS1128: Declaration or statement expected.
36-
~
37-
!!! error TS1128: Declaration or statement expected.
3832
foo((x?)=>{return x;})
3933
~~~
4034
!!! error TS2304: Cannot find name 'foo'.

tests/baselines/reference/fatarrowfunctionsErrors.js

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ foo(function () {
2121
return 0;
2222
});
2323
foo((1), { return: 0 });
24-
;
2524
foo(function (x) {
2625
return x;
2726
});
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
tests/cases/compiler/incompleteObjectLiteral1.ts(1,14): error TS1005: ':' expected.
2-
tests/cases/compiler/incompleteObjectLiteral1.ts(1,16): error TS1128: Declaration or statement expected.
32

43

5-
==== tests/cases/compiler/incompleteObjectLiteral1.ts (2 errors) ====
4+
==== tests/cases/compiler/incompleteObjectLiteral1.ts (1 errors) ====
65
var tt = { aa; }
76
~
87
!!! error TS1005: ':' expected.
9-
~
10-
!!! error TS1128: Declaration or statement expected.
118
var x = tt;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
tests/cases/compiler/objectLiteralWithSemicolons1.ts(1,12): error TS1005: ':' expected.
2+
tests/cases/compiler/objectLiteralWithSemicolons1.ts(1,15): error TS1005: ':' expected.
3+
tests/cases/compiler/objectLiteralWithSemicolons1.ts(1,17): error TS2304: Cannot find name 'c'.
4+
5+
6+
==== tests/cases/compiler/objectLiteralWithSemicolons1.ts (3 errors) ====
7+
var v = { a; b; c }
8+
~
9+
!!! error TS1005: ':' expected.
10+
~
11+
!!! error TS1005: ':' expected.
12+
~
13+
!!! error TS2304: Cannot find name 'c'.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//// [objectLiteralWithSemicolons1.ts]
2+
var v = { a; b; c }
3+
4+
//// [objectLiteralWithSemicolons1.js]
5+
var v = { a: , b: , c: c };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests/cases/compiler/objectLiteralWithSemicolons2.ts(2,4): error TS1005: ':' expected.
2+
tests/cases/compiler/objectLiteralWithSemicolons2.ts(3,4): error TS1005: ':' expected.
3+
tests/cases/compiler/objectLiteralWithSemicolons2.ts(4,3): error TS2304: Cannot find name 'c'.
4+
5+
6+
==== tests/cases/compiler/objectLiteralWithSemicolons2.ts (3 errors) ====
7+
var v = {
8+
a;
9+
~
10+
!!! error TS1005: ':' expected.
11+
b;
12+
~
13+
!!! error TS1005: ':' expected.
14+
c
15+
~
16+
!!! error TS2304: Cannot find name 'c'.
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [objectLiteralWithSemicolons2.ts]
2+
var v = {
3+
a;
4+
b;
5+
c
6+
}
7+
8+
//// [objectLiteralWithSemicolons2.js]
9+
var v = {
10+
a: ,
11+
b: ,
12+
c: c
13+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests/cases/compiler/objectLiteralWithSemicolons3.ts(2,4): error TS1005: ':' expected.
2+
tests/cases/compiler/objectLiteralWithSemicolons3.ts(3,4): error TS1005: ':' expected.
3+
tests/cases/compiler/objectLiteralWithSemicolons3.ts(4,4): error TS1005: ':' expected.
4+
5+
6+
==== tests/cases/compiler/objectLiteralWithSemicolons3.ts (3 errors) ====
7+
var v = {
8+
a;
9+
~
10+
!!! error TS1005: ':' expected.
11+
b;
12+
~
13+
!!! error TS1005: ':' expected.
14+
c;
15+
~
16+
!!! error TS1005: ':' expected.
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [objectLiteralWithSemicolons3.ts]
2+
var v = {
3+
a;
4+
b;
5+
c;
6+
}
7+
8+
//// [objectLiteralWithSemicolons3.js]
9+
var v = {
10+
a: ,
11+
b: ,
12+
c:
13+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
tests/cases/compiler/objectLiteralWithSemicolons4.ts(3,1): error TS1005: ':' expected.
2+
3+
4+
==== tests/cases/compiler/objectLiteralWithSemicolons4.ts (1 errors) ====
5+
var v = {
6+
a
7+
;
8+
~
9+
!!! error TS1005: ':' expected.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//// [objectLiteralWithSemicolons4.ts]
2+
var v = {
3+
a
4+
;
5+
6+
//// [objectLiteralWithSemicolons4.js]
7+
var v = {
8+
a:
9+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
tests/cases/compiler/objectLiteralWithSemicolons5.ts(1,20): error TS1005: ',' expected.
2+
tests/cases/compiler/objectLiteralWithSemicolons5.ts(1,25): error TS2304: Cannot find name 'b'.
3+
tests/cases/compiler/objectLiteralWithSemicolons5.ts(1,26): error TS1005: ',' expected.
4+
tests/cases/compiler/objectLiteralWithSemicolons5.ts(1,32): error TS2378: A 'get' accessor must return a value or consist of a single 'throw' statement.
5+
tests/cases/compiler/objectLiteralWithSemicolons5.ts(1,41): error TS1005: ',' expected.
6+
7+
8+
==== tests/cases/compiler/objectLiteralWithSemicolons5.ts (5 errors) ====
9+
var v = { foo() { }; a: b; get baz() { }; }
10+
~
11+
!!! error TS1005: ',' expected.
12+
~
13+
!!! error TS2304: Cannot find name 'b'.
14+
~
15+
!!! error TS1005: ',' expected.
16+
~~~
17+
!!! error TS2378: A 'get' accessor must return a value or consist of a single 'throw' statement.
18+
~
19+
!!! error TS1005: ',' expected.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//// [objectLiteralWithSemicolons5.ts]
2+
var v = { foo() { }; a: b; get baz() { }; }
3+
4+
//// [objectLiteralWithSemicolons5.js]
5+
var v = { foo: function () {
6+
}, a: b, get baz() {
7+
} };
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512097.ts(1,14): error TS1005: ':' expected.
2-
tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512097.ts(1,16): error TS1128: Declaration or statement expected.
32

43

5-
==== tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512097.ts (2 errors) ====
4+
==== tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512097.ts (1 errors) ====
65
var tt = { aa; } // After this point, no useful parsing occurs in the entire file
76
~
87
!!! error TS1005: ':' expected.
9-
~
10-
!!! error TS1128: Declaration or statement expected.
118

129
if (true) {
1310
}

tests/baselines/reference/parser512097.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ if (true) {
55
}
66

77
//// [parser512097.js]
8-
var tt = { aa: };
8+
var tt = { aa: }; // After this point, no useful parsing occurs in the entire file
99
if (true) {
1010
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral2.ts(2,1): error TS1005: ':' expected.
22
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral2.ts(2,7): error TS1005: ':' expected.
3+
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral2.ts(2,8): error TS1005: '}' expected.
34

45

5-
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral2.ts (2 errors) ====
6+
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral2.ts (3 errors) ====
67
var v = { a
78
return;
89
~~~~~~
910
!!! error TS1005: ':' expected.
1011
~
11-
!!! error TS1005: ':' expected.
12+
!!! error TS1005: ':' expected.
13+
14+
!!! error TS1005: '}' expected.
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral3.ts(2,1): error TS1109: Expression expected.
22
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral3.ts(2,7): error TS1005: ':' expected.
3+
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral3.ts(2,8): error TS1005: '}' expected.
34

45

5-
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral3.ts (2 errors) ====
6+
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral3.ts (3 errors) ====
67
var v = { a:
78
return;
89
~~~~~~
910
!!! error TS1109: Expression expected.
1011
~
11-
!!! error TS1005: ':' expected.
12+
!!! error TS1005: ':' expected.
13+
14+
!!! error TS1005: '}' expected.
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral4.ts(2,1): error TS1005: ',' expected.
22
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral4.ts(2,7): error TS1005: ':' expected.
3+
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral4.ts(2,8): error TS1005: '}' expected.
34

45

5-
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral4.ts (2 errors) ====
6+
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral4.ts (3 errors) ====
67
var v = { a: 1
78
return;
89
~~~~~~
910
!!! error TS1005: ',' expected.
1011
~
11-
!!! error TS1005: ':' expected.
12+
!!! error TS1005: ':' expected.
13+
14+
!!! error TS1005: '}' expected.
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral5.ts(2,7): error TS1005: ':' expected.
2+
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral5.ts(2,8): error TS1005: '}' expected.
23

34

4-
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral5.ts (1 errors) ====
5+
==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ObjectLiterals/parserErrorRecovery_ObjectLiteral5.ts (2 errors) ====
56
var v = { a: 1,
67
return;
78
~
8-
!!! error TS1005: ':' expected.
9+
!!! error TS1005: ':' expected.
10+
11+
!!! error TS1005: '}' expected.

tests/baselines/reference/privateIndexer2.errors.txt

+1-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(4,17)
33
tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(4,23): error TS1005: ',' expected.
44
tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(4,24): error TS1136: Property assignment expected.
55
tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(4,32): error TS1005: ':' expected.
6-
tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(5,1): error TS1128: Declaration or statement expected.
76

87

9-
==== tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts (6 errors) ====
8+
==== tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts (5 errors) ====
109
// private indexers not allowed
1110

1211
var x = {
@@ -22,8 +21,6 @@ tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(5,1):
2221
~
2322
!!! error TS1005: ':' expected.
2423
}
25-
~
26-
!!! error TS1128: Declaration or statement expected.
2724

2825
var y: {
2926
private[x: string]: string;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
var v = { a; b; c }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
var v = {
2+
a;
3+
b;
4+
c
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
var v = {
2+
a;
3+
b;
4+
c;
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
var v = {
2+
a
3+
;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
var v = { foo() { }; a: b; get baz() { }; }

0 commit comments

Comments
 (0)