diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index cbe589f5f0..54f7a806f3 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3533,16 +3533,13 @@ module ts { function parseClassDeclaration(pos: number, flags: NodeFlags): ClassDeclaration { var node = createNode(SyntaxKind.ClassDeclaration, pos); node.flags = flags; - var errorCountBeforeClassDeclaration = file._parserDiagnostics.length; parseExpected(SyntaxKind.ClassKeyword); node.name = parseIdentifier(); node.typeParameters = parseTypeParameters(); // TODO(jfreeman): Parse arbitrary sequence of heritage clauses and error for order and duplicates + node.baseType = parseOptional(SyntaxKind.ExtendsKeyword) ? parseTypeReference() : undefined; - var implementsKeywordStart = scanner.getTokenPos(); - var implementsKeywordLength: number; if (parseOptional(SyntaxKind.ImplementsKeyword)) { - implementsKeywordLength = scanner.getStartPos() - implementsKeywordStart; node.implementedTypes = parseDelimitedList(ParsingContext.BaseTypeReferences, parseTypeReference); } var errorCountBeforeClassBody = file._parserDiagnostics.length; @@ -3553,31 +3550,20 @@ module ts { else { node.members = createMissingList(); } - if (node.implementedTypes && !node.implementedTypes.length && errorCountBeforeClassBody === errorCountBeforeClassDeclaration) { - grammarErrorAtPos(implementsKeywordStart, implementsKeywordLength, Diagnostics._0_list_cannot_be_empty, "implements"); - } return finishNode(node); } function parseInterfaceDeclaration(pos: number, flags: NodeFlags): InterfaceDeclaration { var node = createNode(SyntaxKind.InterfaceDeclaration, pos); node.flags = flags; - var errorCountBeforeInterfaceDeclaration = file._parserDiagnostics.length; parseExpected(SyntaxKind.InterfaceKeyword); node.name = parseIdentifier(); node.typeParameters = parseTypeParameters(); // TODO(jfreeman): Parse arbitrary sequence of heritage clauses and error for order and duplicates - var extendsKeywordStart = scanner.getTokenPos(); - var extendsKeywordLength: number; if (parseOptional(SyntaxKind.ExtendsKeyword)) { - extendsKeywordLength = scanner.getStartPos() - extendsKeywordStart; node.baseTypes = parseDelimitedList(ParsingContext.BaseTypeReferences, parseTypeReference); } - var errorCountBeforeInterfaceBody = file._parserDiagnostics.length; node.members = parseTypeLiteral().members; - if (node.baseTypes && !node.baseTypes.length && errorCountBeforeInterfaceBody === errorCountBeforeInterfaceDeclaration) { - grammarErrorAtPos(extendsKeywordStart, extendsKeywordLength, Diagnostics._0_list_cannot_be_empty, "extends"); - } return finishNode(node); } @@ -4152,7 +4138,14 @@ module ts { } function visitClassDeclaration(node: ClassDeclaration) { - checkForTrailingComma(node.implementedTypes); + checkForTrailingComma(node.implementedTypes) || + checkForAtLeastOneHeritageClause(node.implementedTypes, "implements"); + } + + function checkForAtLeastOneHeritageClause(types: NodeArray, listType: string): boolean { + if (types && types.length === 0) { + return grammarErrorAtPos(types.pos, 0, Diagnostics._0_list_cannot_be_empty, listType) + } } function visitConstructor(node: ConstructorDeclaration) { @@ -4315,7 +4308,8 @@ module ts { } function visitInterfaceDeclaration(node: InterfaceDeclaration) { - checkForTrailingComma(node.baseTypes); + checkForTrailingComma(node.baseTypes) || + checkForAtLeastOneHeritageClause(node.baseTypes, "extends"); } function visitMethod(node: MethodDeclaration) { diff --git a/tests/baselines/reference/parserErrorRecovery_ExtendsOrImplementsClause4.errors.txt b/tests/baselines/reference/parserErrorRecovery_ExtendsOrImplementsClause4.errors.txt index 6ec231b933..6d637831c4 100644 --- a/tests/baselines/reference/parserErrorRecovery_ExtendsOrImplementsClause4.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_ExtendsOrImplementsClause4.errors.txt @@ -1,10 +1,10 @@ -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ExtendsOrImplementsClauses/parserErrorRecovery_ExtendsOrImplementsClause4.ts(1,19): error TS1097: 'implements' list cannot be empty. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ExtendsOrImplementsClauses/parserErrorRecovery_ExtendsOrImplementsClause4.ts(1,29): error TS1097: 'implements' list cannot be empty. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ExtendsOrImplementsClauses/parserErrorRecovery_ExtendsOrImplementsClause4.ts(1,17): error TS2304: Cannot find name 'A'. ==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ExtendsOrImplementsClauses/parserErrorRecovery_ExtendsOrImplementsClause4.ts (2 errors) ==== class C extends A implements { - ~~~~~~~~~~ + !!! error TS1097: 'implements' list cannot be empty. ~ !!! error TS2304: Cannot find name 'A'. diff --git a/tests/baselines/reference/parserErrorRecovery_ExtendsOrImplementsClause6.errors.txt b/tests/baselines/reference/parserErrorRecovery_ExtendsOrImplementsClause6.errors.txt index 1f235691df..2f7ca3d99a 100644 --- a/tests/baselines/reference/parserErrorRecovery_ExtendsOrImplementsClause6.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_ExtendsOrImplementsClause6.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ExtendsOrImplementsClauses/parserErrorRecovery_ExtendsOrImplementsClause6.ts(1,13): error TS1097: 'extends' list cannot be empty. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ExtendsOrImplementsClauses/parserErrorRecovery_ExtendsOrImplementsClause6.ts(1,20): error TS1097: 'extends' list cannot be empty. ==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ExtendsOrImplementsClauses/parserErrorRecovery_ExtendsOrImplementsClause6.ts (1 errors) ==== interface I extends { } - ~~~~~~~ + !!! error TS1097: 'extends' list cannot be empty. \ No newline at end of file