Skip to content

Commit 5d577df

Browse files
committed
Add better error recovery logic for cases with line ending with "id." followed by a declaration e.g. "class id"
1 parent 085cabf commit 5d577df

File tree

4 files changed

+37
-9
lines changed

4 files changed

+37
-9
lines changed

src/compiler/parser.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2198,10 +2198,38 @@ module ts {
21982198

21992199
function parseCallAndAccess(expr: Expression, inNewExpression: boolean): Expression {
22002200
while (true) {
2201+
var dotStart = scanner.getTokenPos();
22012202
if (parseOptional(SyntaxKind.DotToken)) {
22022203
var propertyAccess = <PropertyAccess>createNode(SyntaxKind.PropertyAccess, expr.pos);
2204+
// Technically a keyword is valid here as all keywords are identifier names.
2205+
// However, often we'll encounter this in error situations when the keyword
2206+
// is actually starting another valid construct.
2207+
//
2208+
// So, we check for the following specific case:
2209+
//
2210+
// name.
2211+
// keyword identifierNameOrKeyword
2212+
//
2213+
// Note: the newlines are important here. For example, if that above code
2214+
// were rewritten into:
2215+
//
2216+
// name.keyword
2217+
// identifierNameOrKeyword
2218+
//
2219+
// Then we would consider it valid. That's because ASI would take effect and
2220+
// the code would be implicitly: "name.keyword; identifierNameOrKeyword".
2221+
// In the first case though, ASI will not take effect because there is not a
2222+
// line terminator after the keyword.
2223+
if (scanner.hasPrecedingLineBreak() && scanner.isReservedWord() && lookAhead(() => scanner.isReservedWord())) {
2224+
grammarErrorAtPos(dotStart, scanner.getStartPos() - dotStart, Diagnostics.Identifier_expected);
2225+
var id = <Identifier>createMissingNode();
2226+
}
2227+
else {
2228+
var id = parseIdentifierName();
2229+
}
2230+
22032231
propertyAccess.left = expr;
2204-
propertyAccess.right = parseIdentifierName();
2232+
propertyAccess.right = id;
22052233
expr = finishNode(propertyAccess);
22062234
continue;
22072235
}

tests/baselines/reference/enumConflictsWithGlobalIdentifier.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
IgnoreRulesSpecific = 0,
44
}
55
var x = IgnoreRulesSpecific.
6+
~
7+
!!! Identifier expected.
68
~~~~~~~~~~~~~~~~~~~
79
!!! Cannot find name 'IgnoreRulesSpecific'.
810
var y = Position.IgnoreRulesSpecific;
9-
~
10-
!!! ',' expected.
1111

tests/baselines/reference/enumMemberResolution.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
IgnoreRulesSpecific = 0
44
}
55
var x = IgnoreRulesSpecific. // error
6+
~
7+
!!! Identifier expected.
68
~~~~~~~~~~~~~~~~~~~
79
!!! Cannot find name 'IgnoreRulesSpecific'.
810
var y = 1;
9-
~
10-
!!! ',' expected.
1111
var z = Position2.IgnoreRulesSpecific; // no error
1212

tests/cases/fourslash/memberListOfModuleBeforeKeyword.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616

1717
// Verify the memberlist of module when the following line has a keyword
1818
goTo.marker('namedType');
19-
verify.completionListContains('C1', 'TypeModule1.C1');
20-
verify.completionListContains('C2', 'TypeModule1.C2');
19+
verify.completionListContains('C1');
20+
verify.completionListContains('C2');
2121

2222
goTo.marker('dotedExpression');
23-
verify.completionListContains('C1', 'TypeModule1.C1');
24-
verify.completionListContains('C2', 'TypeModule1.C2');
23+
verify.completionListContains('C1');
24+
verify.completionListContains('C2');

0 commit comments

Comments
 (0)