Skip to content

Commit 0245211

Browse files
Merge pull request #2567 from Microsoft/classExpressions
Add support for parsing and emitting class expressions.
2 parents f239bbc + afc38c2 commit 0245211

File tree

124 files changed

+8252
-1068
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

124 files changed

+8252
-1068
lines changed

src/compiler/binder.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ module ts {
168168
addDeclarationToSymbol(symbol, node, includes);
169169
symbol.parent = parent;
170170

171-
if (node.kind === SyntaxKind.ClassDeclaration && symbol.exports) {
171+
if ((node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression) && symbol.exports) {
172172
// TypeScript 1.0 spec (April 2014): 8.4
173173
// Every class automatically contains a static property member named 'prototype',
174174
// the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter.
@@ -286,6 +286,7 @@ module ts {
286286
case SyntaxKind.ArrowFunction:
287287
declareSymbol(container.locals, undefined, node, symbolKind, symbolExcludes);
288288
break;
289+
case SyntaxKind.ClassExpression:
289290
case SyntaxKind.ClassDeclaration:
290291
if (node.flags & NodeFlags.Static) {
291292
declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes);
@@ -485,6 +486,9 @@ module ts {
485486
case SyntaxKind.ArrowFunction:
486487
bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, "__function", /*isBlockScopeContainer*/ true);
487488
break;
489+
case SyntaxKind.ClassExpression:
490+
bindAnonymousDeclaration(<ClassExpression>node, SymbolFlags.Class, "__class", /*isBlockScopeContainer*/ false);
491+
break;
488492
case SyntaxKind.CatchClause:
489493
bindCatchVariableDeclaration(<CatchClause>node);
490494
break;
@@ -584,9 +588,9 @@ module ts {
584588
// containing class.
585589
if (node.flags & NodeFlags.AccessibilityModifier &&
586590
node.parent.kind === SyntaxKind.Constructor &&
587-
node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
591+
(node.parent.parent.kind === SyntaxKind.ClassDeclaration || node.parent.parent.kind === SyntaxKind.ClassExpression)) {
588592

589-
let classDeclaration = <ClassDeclaration>node.parent.parent;
593+
let classDeclaration = <ClassLikeDeclaration>node.parent.parent;
590594
declareSymbol(classDeclaration.symbol.members, classDeclaration.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
591595
}
592596
}

src/compiler/checker.ts

Lines changed: 196 additions & 98 deletions
Large diffs are not rendered by default.

src/compiler/declarationEmitter.ts

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -314,12 +314,12 @@ module ts {
314314
}
315315
}
316316

317-
function emitTypeWithNewGetSymbolAccessibilityDiagnostic(type: TypeNode | EntityName, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
317+
function emitTypeWithNewGetSymbolAccessibilityDiagnostic(type: TypeNode | EntityName | HeritageClauseElement, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
318318
writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
319319
emitType(type);
320320
}
321321

322-
function emitType(type: TypeNode | StringLiteralExpression | Identifier | QualifiedName) {
322+
function emitType(type: TypeNode | StringLiteralExpression | Identifier | QualifiedName | HeritageClauseElement) {
323323
switch (type.kind) {
324324
case SyntaxKind.AnyKeyword:
325325
case SyntaxKind.StringKeyword:
@@ -329,6 +329,8 @@ module ts {
329329
case SyntaxKind.VoidKeyword:
330330
case SyntaxKind.StringLiteral:
331331
return writeTextOfNode(currentSourceFile, type);
332+
case SyntaxKind.HeritageClauseElement:
333+
return emitHeritageClauseElement(<HeritageClauseElement>type);
332334
case SyntaxKind.TypeReference:
333335
return emitTypeReference(<TypeReferenceNode>type);
334336
case SyntaxKind.TypeQuery:
@@ -350,27 +352,38 @@ module ts {
350352
return emitEntityName(<Identifier>type);
351353
case SyntaxKind.QualifiedName:
352354
return emitEntityName(<QualifiedName>type);
353-
default:
354-
Debug.fail("Unknown type annotation: " + type.kind);
355355
}
356356

357-
function emitEntityName(entityName: EntityName) {
357+
function emitEntityName(entityName: EntityName | PropertyAccessExpression) {
358358
let visibilityResult = resolver.isEntityNameVisible(entityName,
359359
// Aliases can be written asynchronously so use correct enclosing declaration
360360
entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration ? entityName.parent : enclosingDeclaration);
361361

362362
handleSymbolAccessibilityError(visibilityResult);
363363
writeEntityName(entityName);
364364

365-
function writeEntityName(entityName: EntityName) {
365+
function writeEntityName(entityName: EntityName | Expression) {
366366
if (entityName.kind === SyntaxKind.Identifier) {
367367
writeTextOfNode(currentSourceFile, entityName);
368368
}
369369
else {
370-
let qualifiedName = <QualifiedName>entityName;
371-
writeEntityName(qualifiedName.left);
370+
let left = entityName.kind === SyntaxKind.QualifiedName ? (<QualifiedName>entityName).left : (<PropertyAccessExpression>entityName).expression;
371+
let right = entityName.kind === SyntaxKind.QualifiedName ? (<QualifiedName>entityName).right : (<PropertyAccessExpression>entityName).name;
372+
writeEntityName(left);
372373
write(".");
373-
writeTextOfNode(currentSourceFile, qualifiedName.right);
374+
writeTextOfNode(currentSourceFile, right);
375+
}
376+
}
377+
}
378+
379+
function emitHeritageClauseElement(node: HeritageClauseElement) {
380+
if (isSupportedHeritageClauseElement(node)) {
381+
Debug.assert(node.expression.kind === SyntaxKind.Identifier || node.expression.kind === SyntaxKind.PropertyAccessExpression);
382+
emitEntityName(<Identifier | PropertyAccessExpression>node.expression);
383+
if (node.typeArguments) {
384+
write("<");
385+
emitCommaList(node.typeArguments, emitType);
386+
write(">");
374387
}
375388
}
376389
}
@@ -827,14 +840,16 @@ module ts {
827840
}
828841
}
829842

830-
function emitHeritageClause(typeReferences: TypeReferenceNode[], isImplementsList: boolean) {
843+
function emitHeritageClause(typeReferences: HeritageClauseElement[], isImplementsList: boolean) {
831844
if (typeReferences) {
832845
write(isImplementsList ? " implements " : " extends ");
833846
emitCommaList(typeReferences, emitTypeOfTypeReference);
834847
}
835848

836-
function emitTypeOfTypeReference(node: TypeReferenceNode) {
837-
emitTypeWithNewGetSymbolAccessibilityDiagnostic(node, getHeritageClauseVisibilityError);
849+
function emitTypeOfTypeReference(node: HeritageClauseElement) {
850+
if (isSupportedHeritageClauseElement(node)) {
851+
emitTypeWithNewGetSymbolAccessibilityDiagnostic(node, getHeritageClauseVisibilityError);
852+
}
838853

839854
function getHeritageClauseVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
840855
let diagnosticMessage: DiagnosticMessage;
@@ -877,11 +892,11 @@ module ts {
877892
let prevEnclosingDeclaration = enclosingDeclaration;
878893
enclosingDeclaration = node;
879894
emitTypeParameters(node.typeParameters);
880-
let baseTypeNode = getClassBaseTypeNode(node);
895+
let baseTypeNode = getClassExtendsHeritageClauseElement(node);
881896
if (baseTypeNode) {
882897
emitHeritageClause([baseTypeNode], /*isImplementsList*/ false);
883898
}
884-
emitHeritageClause(getClassImplementedTypeNodes(node), /*isImplementsList*/ true);
899+
emitHeritageClause(getClassImplementsHeritageClauseElements(node), /*isImplementsList*/ true);
885900
write(" {");
886901
writeLine();
887902
increaseIndent();

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ module ts {
353353
The_arguments_object_cannot_be_referenced_in_an_arrow_function_Consider_using_a_standard_function_expression: { code: 2496, category: DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an arrow function. Consider using a standard function expression." },
354354
External_module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct: { code: 2497, category: DiagnosticCategory.Error, key: "External module '{0}' resolves to a non-module entity and cannot be imported using this construct." },
355355
External_module_0_uses_export_and_cannot_be_used_with_export_Asterisk: { code: 2498, category: DiagnosticCategory.Error, key: "External module '{0}' uses 'export =' and cannot be used with 'export *'." },
356+
An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments: { code: 2499, category: DiagnosticCategory.Error, key: "An interface can only extend an identifier/qualified-name with optional type arguments." },
357+
A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments: { code: 2500, category: DiagnosticCategory.Error, key: "A class can only implement an identifier/qualified-name with optional type arguments." },
356358
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
357359
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
358360
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },
@@ -505,5 +507,8 @@ module ts {
505507
You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library: { code: 8001, category: DiagnosticCategory.Error, key: "You cannot rename elements that are defined in the standard TypeScript library." },
506508
yield_expressions_are_not_currently_supported: { code: 9000, category: DiagnosticCategory.Error, key: "'yield' expressions are not currently supported." },
507509
Generators_are_not_currently_supported: { code: 9001, category: DiagnosticCategory.Error, key: "Generators are not currently supported." },
510+
Only_identifiers_Slashqualified_names_with_optional_type_arguments_are_currently_supported_in_a_class_extends_clauses: { code: 9002, category: DiagnosticCategory.Error, key: "Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clauses." },
511+
class_expressions_are_not_currently_supported: { code: 9003, category: DiagnosticCategory.Error, key: "'class' expressions are not currently supported." },
512+
class_declarations_are_only_supported_directly_inside_a_module_or_as_a_top_level_declaration: { code: 9004, category: DiagnosticCategory.Error, key: "'class' declarations are only supported directly inside a module or as a top level declaration." },
508513
};
509514
}

src/compiler/diagnosticMessages.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,6 +1403,14 @@
14031403
"category": "Error",
14041404
"code": 2498
14051405
},
1406+
"An interface can only extend an identifier/qualified-name with optional type arguments.": {
1407+
"category": "Error",
1408+
"code": 2499
1409+
},
1410+
"A class can only implement an identifier/qualified-name with optional type arguments.": {
1411+
"category": "Error",
1412+
"code": 2500
1413+
},
14061414

14071415
"Import declaration '{0}' is using private name '{1}'.": {
14081416
"category": "Error",
@@ -2012,5 +2020,17 @@
20122020
"Generators are not currently supported.": {
20132021
"category": "Error",
20142022
"code": 9001
2023+
},
2024+
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clauses.": {
2025+
"category": "Error",
2026+
"code": 9002
2027+
},
2028+
"'class' expressions are not currently supported.": {
2029+
"category": "Error",
2030+
"code": 9003
2031+
},
2032+
"'class' declarations are only supported directly inside a module or as a top level declaration.": {
2033+
"category": "Error",
2034+
"code": 9004
20152035
}
20162036
}

0 commit comments

Comments
 (0)