Skip to content

Commit a2c1adf

Browse files
committed
Permit abstract modifier on class expressions
1 parent 4a39972 commit a2c1adf

File tree

3 files changed

+21
-26
lines changed

3 files changed

+21
-26
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38980,15 +38980,14 @@ namespace ts {
3898038980
if (flags & ModifierFlags.Abstract) {
3898138981
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "abstract");
3898238982
}
38983-
// An abstract modifier is permitted on a class expression in a 'typeof abstract class {}' type
3898438983
if (node.kind !== SyntaxKind.ClassDeclaration && node.kind !== SyntaxKind.ClassExpression) {
3898538984
if (node.kind !== SyntaxKind.MethodDeclaration &&
3898638985
node.kind !== SyntaxKind.PropertyDeclaration &&
3898738986
node.kind !== SyntaxKind.GetAccessor &&
3898838987
node.kind !== SyntaxKind.SetAccessor) {
3898938988
return grammarErrorOnNode(modifier, Diagnostics.abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration);
3899038989
}
38991-
if (!(node.parent.kind === SyntaxKind.ClassDeclaration && hasSyntacticModifier(node.parent, ModifierFlags.Abstract))) {
38990+
if (!((node.parent.kind === SyntaxKind.ClassDeclaration || node.parent.kind === SyntaxKind.ClassExpression) && hasSyntacticModifier(node.parent, ModifierFlags.Abstract))) {
3899238991
return grammarErrorOnNode(modifier, Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class);
3899338992
}
3899438993
if (flags & ModifierFlags.Static) {
@@ -39096,7 +39095,6 @@ namespace ts {
3909639095
return nodeHasAnyModifiersExcept(node, SyntaxKind.AsyncKeyword);
3909739096
case SyntaxKind.ClassDeclaration:
3909839097
case SyntaxKind.ClassExpression:
39099-
// An abstract modifier is permitted on a class expression in a 'typeof abstract class {}' type
3910039098
return nodeHasAnyModifiersExcept(node, SyntaxKind.AbstractKeyword);
3910139099
case SyntaxKind.InterfaceDeclaration:
3910239100
case SyntaxKind.VariableStatement:

src/compiler/parser.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2861,22 +2861,14 @@ namespace ts {
28612861
}
28622862

28632863
function isStartOfTypeofClassExpression() {
2864-
return token() === SyntaxKind.ClassKeyword ||
2865-
token() === SyntaxKind.AbstractKeyword && lookAhead(() => nextToken() === SyntaxKind.ClassKeyword && !scanner.hasPrecedingLineBreak());
2866-
}
2867-
2868-
function parseTypeofClassExpression(): ClassExpression {
2869-
const pos = getNodePos();
2870-
const hasJSDoc = hasPrecedingJSDocComment();
2871-
const modifiers = parseModifiers();
2872-
return <ClassExpression>parseClassDeclarationOrExpression(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.ClassExpression);
2864+
return token() === SyntaxKind.ClassKeyword || token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine);
28732865
}
28742866

28752867
function parseTypeQuery(): TypeQueryNode {
28762868
const pos = getNodePos();
28772869
parseExpected(SyntaxKind.TypeOfKeyword);
28782870
return finishNode(factory.createTypeQueryNode(isStartOfTypeofClassExpression() ?
2879-
doInsideOfContext(NodeFlags.Ambient, parseTypeofClassExpression) :
2871+
doInsideOfContext(NodeFlags.Ambient, parseClassExpression) :
28802872
parseEntityName(/*allowReservedWords*/ true)), pos);
28812873
}
28822874

@@ -5323,6 +5315,11 @@ namespace ts {
53235315
}
53245316

53255317
return parseFunctionExpression();
5318+
case SyntaxKind.AbstractKeyword:
5319+
if (!lookAhead(nextTokenIsClassKeywordOnSameLine)) {
5320+
break;
5321+
}
5322+
// Fall through
53265323
case SyntaxKind.ClassKeyword:
53275324
return parseClassExpression();
53285325
case SyntaxKind.FunctionKeyword:
@@ -6654,7 +6651,10 @@ namespace ts {
66546651
}
66556652

66566653
function parseClassExpression(): ClassExpression {
6657-
return <ClassExpression>parseClassDeclarationOrExpression(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined, SyntaxKind.ClassExpression);
6654+
const pos = getNodePos();
6655+
const hasJSDoc = hasPrecedingJSDocComment();
6656+
const modifiers = parseModifiers();
6657+
return <ClassExpression>parseClassDeclarationOrExpression(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.ClassExpression);
66586658
}
66596659

66606660
function parseClassDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ClassDeclaration {

src/services/documentHighlights.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ namespace ts {
204204

205205
function getNodesToSearchForModifier(declaration: Node, modifierFlag: ModifierFlags): readonly Node[] | undefined {
206206
// Types of node whose children might have modifiers.
207-
const container = declaration.parent as ModuleBlock | SourceFile | Block | CaseClause | DefaultClause | ConstructorDeclaration | MethodDeclaration | FunctionDeclaration | ObjectTypeDeclaration | ObjectLiteralExpression;
207+
const container = declaration.parent;
208208
switch (container.kind) {
209209
case SyntaxKind.ModuleBlock:
210210
case SyntaxKind.SourceFile:
@@ -216,22 +216,21 @@ namespace ts {
216216
return [...declaration.members, declaration];
217217
}
218218
else {
219-
return container.statements;
219+
return (<ModuleBlock | SourceFile | Block | CaseClause | DefaultClause>container).statements;
220220
}
221221
case SyntaxKind.Constructor:
222222
case SyntaxKind.MethodDeclaration:
223223
case SyntaxKind.FunctionDeclaration:
224-
return [...container.parameters, ...(isClassLike(container.parent) ? container.parent.members : [])];
224+
return [...(<ConstructorDeclaration | MethodDeclaration | FunctionDeclaration>container).parameters, ...(isClassLike(container.parent) ? container.parent.members : [])];
225225
case SyntaxKind.ClassDeclaration:
226226
case SyntaxKind.ClassExpression:
227227
case SyntaxKind.InterfaceDeclaration:
228228
case SyntaxKind.TypeLiteral:
229-
const nodes = container.members;
230-
229+
const nodes = (<ClassDeclaration | ClassExpression | InterfaceDeclaration | TypeLiteralNode>container).members;
231230
// If we're an accessibility modifier, we're in an instance member and should search
232231
// the constructor's parameter list for instance members as well.
233232
if (modifierFlag & (ModifierFlags.AccessibilityModifier | ModifierFlags.Readonly)) {
234-
const constructor = find(container.members, isConstructorDeclaration);
233+
const constructor = find(nodes, isConstructorDeclaration);
235234
if (constructor) {
236235
return [...nodes, ...constructor.parameters];
237236
}
@@ -240,13 +239,11 @@ namespace ts {
240239
return [...nodes, container];
241240
}
242241
return nodes;
243-
244-
// Syntactically invalid positions that the parser might produce anyway
245-
case SyntaxKind.ObjectLiteralExpression:
246-
return undefined;
247-
248242
default:
249-
Debug.assertNever(container, "Invalid container kind.");
243+
if (modifierFlag & ModifierFlags.Abstract && isClassExpression(declaration)) {
244+
return [...declaration.members, declaration];
245+
}
246+
return undefined;
250247
}
251248
}
252249

0 commit comments

Comments
 (0)