Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2880,7 +2880,7 @@ namespace Parser {
case ParsingContext.ImportAttributes:
return isImportAttributeName();
case ParsingContext.HeritageClauseElement:
// If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{`
// If we see `{ ... }` then only consume it as an expression if it is followed by `,`, `.`, `!`, `{`, `extends` or `implements`.
// That way we won't consume the body of a class in its heritage clause.
if (token() === SyntaxKind.OpenBraceToken) {
return lookAhead(isValidHeritageClauseObjectLiteral);
Expand Down Expand Up @@ -2946,15 +2946,17 @@ namespace Parser {
Debug.assert(token() === SyntaxKind.OpenBraceToken);
if (nextToken() === SyntaxKind.CloseBraceToken) {
// if we see "extends {}" then only treat the {} as what we're extending (and not
// the class body) if we have:
//
// extends {} {
// extends {},
// extends {} extends
// extends {} implements

const next = nextToken();
return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword;
// the class body) if we have one of those next tokens.
switch (nextToken()) {
case SyntaxKind.CommaToken:
case SyntaxKind.DotToken:
case SyntaxKind.ExclamationToken:
case SyntaxKind.ExtendsKeyword:
case SyntaxKind.ImplementsKeyword:
case SyntaxKind.OpenBraceToken:
return true;
}
return false;
}

return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
parseHeritageClauseEmptyObject1_1.ts(1,18): error TS2507: Type '{}' is not a constructor function type.
parseHeritageClauseEmptyObject1_1.ts(1,32): error TS2304: Cannot find name 'X'.
parseHeritageClauseEmptyObject1_2.ts(1,18): error TS2507: Type '{}' is not a constructor function type.
parseHeritageClauseEmptyObject1_2.ts(1,21): error TS1172: 'extends' clause already seen.
parseHeritageClauseEmptyObject1_3.ts(1,18): error TS2507: Type '{}' is not a constructor function type.
parseHeritageClauseEmptyObject1_3.ts(1,20): error TS1009: Trailing comma not allowed.
parseHeritageClauseEmptyObject1_4.ts(1,18): error TS2507: Type '{}' is not a constructor function type.
parseHeritageClauseEmptyObject1_5.ts(1,21): error TS2339: Property 'Foo' does not exist on type '{}'.
parseHeritageClauseEmptyObject1_6.ts(1,21): error TS2339: Property 'Foo' does not exist on type '{}'.
parseHeritageClauseEmptyObject1_6.ts(1,24): error TS1005: '{' expected.
parseHeritageClauseEmptyObject1_7.ts(1,17): error TS1097: 'extends' list cannot be empty.


==== parseHeritageClauseEmptyObject1_1.ts (2 errors) ====
class C1 extends {} implements X {}
~~
!!! error TS2507: Type '{}' is not a constructor function type.
~
!!! error TS2304: Cannot find name 'X'.
==== parseHeritageClauseEmptyObject1_2.ts (2 errors) ====
class C2 extends {} extends X {}
~~
!!! error TS2507: Type '{}' is not a constructor function type.
~~~~~~~
!!! error TS1172: 'extends' clause already seen.
==== parseHeritageClauseEmptyObject1_3.ts (2 errors) ====
class C3 extends {}, {}
~~
!!! error TS2507: Type '{}' is not a constructor function type.
~
!!! error TS1009: Trailing comma not allowed.
==== parseHeritageClauseEmptyObject1_4.ts (1 errors) ====
class C4 extends {}! {}
~~~
!!! error TS2507: Type '{}' is not a constructor function type.
==== parseHeritageClauseEmptyObject1_5.ts (1 errors) ====
class C5 extends {}.Foo {}
~~~
!!! error TS2339: Property 'Foo' does not exist on type '{}'.
==== parseHeritageClauseEmptyObject1_6.ts (2 errors) ====
class C6 extends {}.Foo
~~~
!!! error TS2339: Property 'Foo' does not exist on type '{}'.

!!! error TS1005: '{' expected.
==== parseHeritageClauseEmptyObject1_7.ts (1 errors) ====
class C7 extends {}

!!! error TS1097: 'extends' list cannot be empty.

46 changes: 46 additions & 0 deletions tests/baselines/reference/parseHeritageClauseEmptyObject1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//// [tests/cases/compiler/parseHeritageClauseEmptyObject1.ts] ////

//// [parseHeritageClauseEmptyObject1_1.ts]
class C1 extends {} implements X {}
//// [parseHeritageClauseEmptyObject1_2.ts]
class C2 extends {} extends X {}
//// [parseHeritageClauseEmptyObject1_3.ts]
class C3 extends {}, {}
//// [parseHeritageClauseEmptyObject1_4.ts]
class C4 extends {}! {}
//// [parseHeritageClauseEmptyObject1_5.ts]
class C5 extends {}.Foo {}
//// [parseHeritageClauseEmptyObject1_6.ts]
class C6 extends {}.Foo
//// [parseHeritageClauseEmptyObject1_7.ts]
class C7 extends {}


//// [parseHeritageClauseEmptyObject1_1.js]
"use strict";
class C1 extends {} {
}
//// [parseHeritageClauseEmptyObject1_2.js]
"use strict";
class C2 extends {} extends X {
}
//// [parseHeritageClauseEmptyObject1_3.js]
"use strict";
class C3 extends {} {
}
//// [parseHeritageClauseEmptyObject1_4.js]
"use strict";
class C4 extends {} {
}
//// [parseHeritageClauseEmptyObject1_5.js]
"use strict";
class C5 extends {}.Foo {
}
//// [parseHeritageClauseEmptyObject1_6.js]
"use strict";
class C6 extends {}.Foo {
}
//// [parseHeritageClauseEmptyObject1_7.js]
"use strict";
class C7 extends {
}
30 changes: 30 additions & 0 deletions tests/baselines/reference/parseHeritageClauseEmptyObject1.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//// [tests/cases/compiler/parseHeritageClauseEmptyObject1.ts] ////

=== parseHeritageClauseEmptyObject1_1.ts ===
class C1 extends {} implements X {}
>C1 : Symbol(C1, Decl(parseHeritageClauseEmptyObject1_1.ts, 0, 0))

=== parseHeritageClauseEmptyObject1_2.ts ===
class C2 extends {} extends X {}
>C2 : Symbol(C2, Decl(parseHeritageClauseEmptyObject1_2.ts, 0, 0))

=== parseHeritageClauseEmptyObject1_3.ts ===
class C3 extends {}, {}
>C3 : Symbol(C3, Decl(parseHeritageClauseEmptyObject1_3.ts, 0, 0))

=== parseHeritageClauseEmptyObject1_4.ts ===
class C4 extends {}! {}
>C4 : Symbol(C4, Decl(parseHeritageClauseEmptyObject1_4.ts, 0, 0))

=== parseHeritageClauseEmptyObject1_5.ts ===
class C5 extends {}.Foo {}
>C5 : Symbol(C5, Decl(parseHeritageClauseEmptyObject1_5.ts, 0, 0))

=== parseHeritageClauseEmptyObject1_6.ts ===
class C6 extends {}.Foo
>C6 : Symbol(C6, Decl(parseHeritageClauseEmptyObject1_6.ts, 0, 0))

=== parseHeritageClauseEmptyObject1_7.ts ===
class C7 extends {}
>C7 : Symbol(C7, Decl(parseHeritageClauseEmptyObject1_7.ts, 0, 0))

61 changes: 61 additions & 0 deletions tests/baselines/reference/parseHeritageClauseEmptyObject1.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//// [tests/cases/compiler/parseHeritageClauseEmptyObject1.ts] ////

=== parseHeritageClauseEmptyObject1_1.ts ===
class C1 extends {} implements X {}
>C1 : C1
> : ^^
>{} : {}
> : ^^

=== parseHeritageClauseEmptyObject1_2.ts ===
class C2 extends {} extends X {}
>C2 : C2
> : ^^
>{} : {}
> : ^^
>X : any
> : ^^^

=== parseHeritageClauseEmptyObject1_3.ts ===
class C3 extends {}, {}
>C3 : C3
> : ^^
>{} : {}
> : ^^

=== parseHeritageClauseEmptyObject1_4.ts ===
class C4 extends {}! {}
>C4 : C4
> : ^^
>{}! : {}
> : ^^
>{} : {}
> : ^^

=== parseHeritageClauseEmptyObject1_5.ts ===
class C5 extends {}.Foo {}
>C5 : C5
> : ^^
>{}.Foo : any
> : ^^^
>{} : {}
> : ^^
>Foo : any
> : ^^^

=== parseHeritageClauseEmptyObject1_6.ts ===
class C6 extends {}.Foo
>C6 : C6
> : ^^
>{}.Foo : any
> : ^^^
>{} : {}
> : ^^
>Foo : any
> : ^^^

=== parseHeritageClauseEmptyObject1_7.ts ===
class C7 extends {}
>C7 : C7
> : ^^

17 changes: 17 additions & 0 deletions tests/cases/compiler/parseHeritageClauseEmptyObject1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @strict: true
// @target: esnext

// @filename: parseHeritageClauseEmptyObject1_1.ts
class C1 extends {} implements X {}
// @filename: parseHeritageClauseEmptyObject1_2.ts
class C2 extends {} extends X {}
// @filename: parseHeritageClauseEmptyObject1_3.ts
class C3 extends {}, {}
// @filename: parseHeritageClauseEmptyObject1_4.ts
class C4 extends {}! {}
// @filename: parseHeritageClauseEmptyObject1_5.ts
class C5 extends {}.Foo {}
// @filename: parseHeritageClauseEmptyObject1_6.ts
class C6 extends {}.Foo
// @filename: parseHeritageClauseEmptyObject1_7.ts
class C7 extends {}