Skip to content

Commit 35d8536

Browse files
Merge pull request #2588 from Microsoft/classExpr
Class declarations should be block scoped.
2 parents feabcd0 + d048d7d commit 35d8536

25 files changed

+178
-28
lines changed

src/compiler/binder.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -388,23 +388,28 @@ module ts {
388388
bindChildren(node, /*symbolKind:*/ 0, /*isBlockScopeContainer:*/ true);
389389
}
390390

391-
function bindBlockScopedVariableDeclaration(node: Declaration) {
391+
function bindBlockScopedDeclaration(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags) {
392392
switch (blockScopeContainer.kind) {
393393
case SyntaxKind.ModuleDeclaration:
394-
declareModuleMember(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
394+
declareModuleMember(node, symbolKind, symbolExcludes);
395395
break;
396396
case SyntaxKind.SourceFile:
397397
if (isExternalModule(<SourceFile>container)) {
398-
declareModuleMember(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
398+
declareModuleMember(node, symbolKind, symbolExcludes);
399399
break;
400400
}
401+
// fall through.
401402
default:
402403
if (!blockScopeContainer.locals) {
403404
blockScopeContainer.locals = {};
404405
}
405-
declareSymbol(blockScopeContainer.locals, undefined, node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
406+
declareSymbol(blockScopeContainer.locals, undefined, node, symbolKind, symbolExcludes);
406407
}
407-
bindChildren(node, SymbolFlags.BlockScopedVariable, /*isBlockScopeContainer*/ false);
408+
bindChildren(node, symbolKind, /*isBlockScopeContainer*/ false);
409+
}
410+
411+
function bindBlockScopedVariableDeclaration(node: Declaration) {
412+
bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
408413
}
409414

410415
function getDestructuringParameterName(node: Declaration) {
@@ -493,7 +498,7 @@ module ts {
493498
bindCatchVariableDeclaration(<CatchClause>node);
494499
break;
495500
case SyntaxKind.ClassDeclaration:
496-
bindDeclaration(<Declaration>node, SymbolFlags.Class, SymbolFlags.ClassExcludes, /*isBlockScopeContainer*/ false);
501+
bindBlockScopedDeclaration(<Declaration>node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
497502
break;
498503
case SyntaxKind.InterfaceDeclaration:
499504
bindDeclaration(<Declaration>node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes, /*isBlockScopeContainer*/ false);

src/compiler/checker.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9760,6 +9760,10 @@ module ts {
97609760
grammarErrorOnNode(node, Diagnostics.class_declarations_are_only_supported_directly_inside_a_module_or_as_a_top_level_declaration);
97619761
}
97629762

9763+
if (!node.name && !(node.flags & NodeFlags.Default)) {
9764+
grammarErrorOnFirstToken(node, Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name);
9765+
}
9766+
97639767
checkGrammarClassDeclarationHeritageClauses(node);
97649768
checkDecorators(node);
97659769
if (node.name) {

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ module ts {
167167
Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name: { code: 1207, category: DiagnosticCategory.Error, key: "Decorators cannot be applied to multiple get/set accessors of the same name." },
168168
Cannot_compile_non_external_modules_when_the_separateCompilation_flag_is_provided: { code: 1208, category: DiagnosticCategory.Error, key: "Cannot compile non-external modules when the '--separateCompilation' flag is provided." },
169169
Ambient_const_enums_are_not_allowed_when_the_separateCompilation_flag_is_provided: { code: 1209, category: DiagnosticCategory.Error, key: "Ambient const enums are not allowed when the '--separateCompilation' flag is provided." },
170+
A_class_declaration_without_the_default_modifier_must_have_a_name: { code: 1210, category: DiagnosticCategory.Error, key: "A class declaration without the 'default' modifier must have a name" },
170171
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
171172
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
172173
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,10 @@
659659
"category": "Error",
660660
"code": 1209
661661
},
662+
"A class declaration without the 'default' modifier must have a name": {
663+
"category": "Error",
664+
"code": 1210
665+
},
662666
"Duplicate identifier '{0}'.": {
663667
"category": "Error",
664668
"code": 2300

src/compiler/emitter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ module ts {
262262
switch (node.kind) {
263263
case SyntaxKind.FunctionDeclaration:
264264
case SyntaxKind.ClassDeclaration:
265+
case SyntaxKind.ClassExpression:
265266
generateNameForFunctionOrClassDeclaration(<Declaration>node);
266267
break;
267268
case SyntaxKind.ModuleDeclaration:

src/compiler/parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4764,7 +4764,7 @@ module ts {
47644764
node.decorators = decorators;
47654765
setModifiers(node, modifiers);
47664766
parseExpected(SyntaxKind.ClassKeyword);
4767-
node.name = node.flags & NodeFlags.Default ? parseOptionalIdentifier() : parseIdentifier();
4767+
node.name = parseOptionalIdentifier();
47684768
node.typeParameters = parseTypeParameters();
47694769
node.heritageClauses = parseHeritageClauses(/*isClassHeritageClause:*/ true);
47704770

src/services/navigationBar.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,10 +418,10 @@ module ts.NavigationBar {
418418
}
419419

420420
function createFunctionItem(node: FunctionDeclaration) {
421-
if ((node.name || node.flags & NodeFlags.Default) && node.body && node.body.kind === SyntaxKind.Block) {
421+
if (node.body && node.body.kind === SyntaxKind.Block) {
422422
let childItems = getItemsWorker(sortNodes((<Block>node.body).statements), createChildItem);
423423

424-
return getNavigationBarItem((!node.name && node.flags & NodeFlags.Default) ? "default": node.name.text ,
424+
return getNavigationBarItem(!node.name ? "default": node.name.text ,
425425
ts.ScriptElementKind.functionElement,
426426
getNodeModifiers(node),
427427
[getNodeSpan(node)],
@@ -470,7 +470,7 @@ module ts.NavigationBar {
470470
childItems = getItemsWorker(sortNodes(nodes), createChildItem);
471471
}
472472

473-
var nodeName = !node.name && (node.flags & NodeFlags.Default) ? "default" : node.name.text;
473+
var nodeName = !node.name ? "default" : node.name.text;
474474

475475
return getNavigationBarItem(
476476
nodeName,
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
tests/cases/compiler/anonymousClassExpression1.ts(2,19): error TS9003: 'class' expressions are not currently supported.
2+
3+
4+
==== tests/cases/compiler/anonymousClassExpression1.ts (1 errors) ====
5+
function f() {
6+
return typeof class {} === "function";
7+
~~~~~
8+
!!! error TS9003: 'class' expressions are not currently supported.
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [anonymousClassExpression1.ts]
2+
function f() {
3+
return typeof class {} === "function";
4+
}
5+
6+
//// [anonymousClassExpression1.js]
7+
function f() {
8+
return typeof (function () {
9+
function default_1() {
10+
}
11+
return default_1;
12+
})() === "function";
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
tests/cases/compiler/classDeclarationBlockScoping1.ts(5,11): error TS9004: 'class' declarations are only supported directly inside a module or as a top level declaration.
2+
3+
4+
==== tests/cases/compiler/classDeclarationBlockScoping1.ts (1 errors) ====
5+
class C {
6+
}
7+
8+
{
9+
class C {
10+
~
11+
!!! error TS9004: 'class' declarations are only supported directly inside a module or as a top level declaration.
12+
}
13+
}

0 commit comments

Comments
 (0)