Skip to content

Commit 5a77d67

Browse files
committed
Merge pull request #4921 from Microsoft/implementsAsIdentifier
disambiguate: 'implements' starts heritage clause vs 'implements' is …
2 parents 1482ade + c56b416 commit 5a77d67

File tree

5 files changed

+71
-2
lines changed

5 files changed

+71
-2
lines changed

src/compiler/parser.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4809,7 +4809,7 @@ namespace ts {
48094809
node.decorators = decorators;
48104810
setModifiers(node, modifiers);
48114811
parseExpected(SyntaxKind.ClassKeyword);
4812-
node.name = parseOptionalIdentifier();
4812+
node.name = parseNameOfClassDeclarationOrExpression();
48134813
node.typeParameters = parseTypeParameters();
48144814
node.heritageClauses = parseHeritageClauses(/*isClassHeritageClause*/ true);
48154815

@@ -4825,7 +4825,22 @@ namespace ts {
48254825

48264826
return finishNode(node);
48274827
}
4828-
4828+
4829+
function parseNameOfClassDeclarationOrExpression(): Identifier {
4830+
// implements is a future reserved word so
4831+
// 'class implements' might mean either
4832+
// - class expression with omitted name, 'implements' starts heritage clause
4833+
// - class with name 'implements'
4834+
// 'isImplementsClause' helps to disambiguate between these two cases
4835+
return isIdentifier() && !isImplementsClause()
4836+
? parseIdentifier()
4837+
: undefined;
4838+
}
4839+
4840+
function isImplementsClause() {
4841+
return token === SyntaxKind.ImplementsKeyword && lookAhead(nextTokenIsIdentifierOrKeyword)
4842+
}
4843+
48294844
function parseHeritageClauses(isClassHeritageClause: boolean): NodeArray<HeritageClause> {
48304845
// ClassTail[Yield,Await] : (Modified) See 14.5
48314846
// ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//// [implementsInClassExpression.ts]
2+
interface Foo {
3+
doThing(): void;
4+
}
5+
6+
let cls = class implements Foo {
7+
doThing() { }
8+
}
9+
10+
//// [implementsInClassExpression.js]
11+
var cls = (function () {
12+
function class_1() {
13+
}
14+
class_1.prototype.doThing = function () { };
15+
return class_1;
16+
})();
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/compiler/implementsInClassExpression.ts ===
2+
interface Foo {
3+
>Foo : Symbol(Foo, Decl(implementsInClassExpression.ts, 0, 0))
4+
5+
doThing(): void;
6+
>doThing : Symbol(doThing, Decl(implementsInClassExpression.ts, 0, 15))
7+
}
8+
9+
let cls = class implements Foo {
10+
>cls : Symbol(cls, Decl(implementsInClassExpression.ts, 4, 3))
11+
>Foo : Symbol(Foo, Decl(implementsInClassExpression.ts, 0, 0))
12+
13+
doThing() { }
14+
>doThing : Symbol((Anonymous class).doThing, Decl(implementsInClassExpression.ts, 4, 32))
15+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/compiler/implementsInClassExpression.ts ===
2+
interface Foo {
3+
>Foo : Foo
4+
5+
doThing(): void;
6+
>doThing : () => void
7+
}
8+
9+
let cls = class implements Foo {
10+
>cls : typeof (Anonymous class)
11+
>class implements Foo { doThing() { }} : typeof (Anonymous class)
12+
>Foo : Foo
13+
14+
doThing() { }
15+
>doThing : () => void
16+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
interface Foo {
2+
doThing(): void;
3+
}
4+
5+
let cls = class implements Foo {
6+
doThing() { }
7+
}

0 commit comments

Comments
 (0)