From 5d577df69e50a03f1edfcbf66b232925d7d1e13c Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 12 Sep 2014 16:48:52 -0700 Subject: [PATCH] Add better error recovery logic for cases with line ending with "id." followed by a declaration e.g. "class id" --- src/compiler/parser.ts | 30 ++++++++++++++++++- ...umConflictsWithGlobalIdentifier.errors.txt | 4 +-- .../reference/enumMemberResolution.errors.txt | 4 +-- .../memberListOfModuleBeforeKeyword.ts | 8 ++--- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 70cdffc75c5..c380c1e0df2 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2198,10 +2198,38 @@ module ts { function parseCallAndAccess(expr: Expression, inNewExpression: boolean): Expression { while (true) { + var dotStart = scanner.getTokenPos(); if (parseOptional(SyntaxKind.DotToken)) { var propertyAccess = createNode(SyntaxKind.PropertyAccess, expr.pos); + // Technically a keyword is valid here as all keywords are identifier names. + // However, often we'll encounter this in error situations when the keyword + // is actually starting another valid construct. + // + // So, we check for the following specific case: + // + // name. + // keyword identifierNameOrKeyword + // + // Note: the newlines are important here. For example, if that above code + // were rewritten into: + // + // name.keyword + // identifierNameOrKeyword + // + // Then we would consider it valid. That's because ASI would take effect and + // the code would be implicitly: "name.keyword; identifierNameOrKeyword". + // In the first case though, ASI will not take effect because there is not a + // line terminator after the keyword. + if (scanner.hasPrecedingLineBreak() && scanner.isReservedWord() && lookAhead(() => scanner.isReservedWord())) { + grammarErrorAtPos(dotStart, scanner.getStartPos() - dotStart, Diagnostics.Identifier_expected); + var id = createMissingNode(); + } + else { + var id = parseIdentifierName(); + } + propertyAccess.left = expr; - propertyAccess.right = parseIdentifierName(); + propertyAccess.right = id; expr = finishNode(propertyAccess); continue; } diff --git a/tests/baselines/reference/enumConflictsWithGlobalIdentifier.errors.txt b/tests/baselines/reference/enumConflictsWithGlobalIdentifier.errors.txt index 7fb893354a9..41e01d6fa4c 100644 --- a/tests/baselines/reference/enumConflictsWithGlobalIdentifier.errors.txt +++ b/tests/baselines/reference/enumConflictsWithGlobalIdentifier.errors.txt @@ -3,9 +3,9 @@ IgnoreRulesSpecific = 0, } var x = IgnoreRulesSpecific. + ~ +!!! Identifier expected. ~~~~~~~~~~~~~~~~~~~ !!! Cannot find name 'IgnoreRulesSpecific'. var y = Position.IgnoreRulesSpecific; - ~ -!!! ',' expected. \ No newline at end of file diff --git a/tests/baselines/reference/enumMemberResolution.errors.txt b/tests/baselines/reference/enumMemberResolution.errors.txt index 71f6f8e45b5..9fa148d849d 100644 --- a/tests/baselines/reference/enumMemberResolution.errors.txt +++ b/tests/baselines/reference/enumMemberResolution.errors.txt @@ -3,10 +3,10 @@ IgnoreRulesSpecific = 0 } var x = IgnoreRulesSpecific. // error + ~ +!!! Identifier expected. ~~~~~~~~~~~~~~~~~~~ !!! Cannot find name 'IgnoreRulesSpecific'. var y = 1; - ~ -!!! ',' expected. var z = Position2.IgnoreRulesSpecific; // no error \ No newline at end of file diff --git a/tests/cases/fourslash/memberListOfModuleBeforeKeyword.ts b/tests/cases/fourslash/memberListOfModuleBeforeKeyword.ts index 2356a35d947..33f085cde03 100644 --- a/tests/cases/fourslash/memberListOfModuleBeforeKeyword.ts +++ b/tests/cases/fourslash/memberListOfModuleBeforeKeyword.ts @@ -16,9 +16,9 @@ // Verify the memberlist of module when the following line has a keyword goTo.marker('namedType'); -verify.completionListContains('C1', 'TypeModule1.C1'); -verify.completionListContains('C2', 'TypeModule1.C2'); +verify.completionListContains('C1'); +verify.completionListContains('C2'); goTo.marker('dotedExpression'); -verify.completionListContains('C1', 'TypeModule1.C1'); -verify.completionListContains('C2', 'TypeModule1.C2'); \ No newline at end of file +verify.completionListContains('C1'); +verify.completionListContains('C2'); \ No newline at end of file