diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 0ae33d08fd..494570c85c 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -388,23 +388,28 @@ module ts { bindChildren(node, /*symbolKind:*/ 0, /*isBlockScopeContainer:*/ true); } - function bindBlockScopedVariableDeclaration(node: Declaration) { + function bindBlockScopedDeclaration(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags) { switch (blockScopeContainer.kind) { case SyntaxKind.ModuleDeclaration: - declareModuleMember(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes); + declareModuleMember(node, symbolKind, symbolExcludes); break; case SyntaxKind.SourceFile: if (isExternalModule(container)) { - declareModuleMember(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes); + declareModuleMember(node, symbolKind, symbolExcludes); break; } + // fall through. default: if (!blockScopeContainer.locals) { blockScopeContainer.locals = {}; } - declareSymbol(blockScopeContainer.locals, undefined, node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes); + declareSymbol(blockScopeContainer.locals, undefined, node, symbolKind, symbolExcludes); } - bindChildren(node, SymbolFlags.BlockScopedVariable, /*isBlockScopeContainer*/ false); + bindChildren(node, symbolKind, /*isBlockScopeContainer*/ false); + } + + function bindBlockScopedVariableDeclaration(node: Declaration) { + bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes); } function getDestructuringParameterName(node: Declaration) { @@ -493,7 +498,7 @@ module ts { bindCatchVariableDeclaration(node); break; case SyntaxKind.ClassDeclaration: - bindDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes, /*isBlockScopeContainer*/ false); + bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes); break; case SyntaxKind.InterfaceDeclaration: bindDeclaration(node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes, /*isBlockScopeContainer*/ false); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3ce7fe5e1c..f0882a51c4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9760,6 +9760,10 @@ module ts { grammarErrorOnNode(node, Diagnostics.class_declarations_are_only_supported_directly_inside_a_module_or_as_a_top_level_declaration); } + if (!node.name && !(node.flags & NodeFlags.Default)) { + grammarErrorOnFirstToken(node, Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); + } + checkGrammarClassDeclarationHeritageClauses(node); checkDecorators(node); if (node.name) { diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 3e9017786e..b141ce607f 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -167,6 +167,7 @@ module ts { 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." }, 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." }, 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." }, + 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" }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, 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." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index f6edb3150b..cafc1f5efa 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -659,6 +659,10 @@ "category": "Error", "code": 1209 }, + "A class declaration without the 'default' modifier must have a name": { + "category": "Error", + "code": 1210 + }, "Duplicate identifier '{0}'.": { "category": "Error", "code": 2300 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 6ec4ea2389..5d4bf9df3e 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -262,6 +262,7 @@ module ts { switch (node.kind) { case SyntaxKind.FunctionDeclaration: case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: generateNameForFunctionOrClassDeclaration(node); break; case SyntaxKind.ModuleDeclaration: diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 2972fba397..7a28ad0441 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4764,7 +4764,7 @@ module ts { node.decorators = decorators; setModifiers(node, modifiers); parseExpected(SyntaxKind.ClassKeyword); - node.name = node.flags & NodeFlags.Default ? parseOptionalIdentifier() : parseIdentifier(); + node.name = parseOptionalIdentifier(); node.typeParameters = parseTypeParameters(); node.heritageClauses = parseHeritageClauses(/*isClassHeritageClause:*/ true); diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index c6463aba73..e475827837 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -418,10 +418,10 @@ module ts.NavigationBar { } function createFunctionItem(node: FunctionDeclaration) { - if ((node.name || node.flags & NodeFlags.Default) && node.body && node.body.kind === SyntaxKind.Block) { + if (node.body && node.body.kind === SyntaxKind.Block) { let childItems = getItemsWorker(sortNodes((node.body).statements), createChildItem); - return getNavigationBarItem((!node.name && node.flags & NodeFlags.Default) ? "default": node.name.text , + return getNavigationBarItem(!node.name ? "default": node.name.text , ts.ScriptElementKind.functionElement, getNodeModifiers(node), [getNodeSpan(node)], @@ -470,7 +470,7 @@ module ts.NavigationBar { childItems = getItemsWorker(sortNodes(nodes), createChildItem); } - var nodeName = !node.name && (node.flags & NodeFlags.Default) ? "default" : node.name.text; + var nodeName = !node.name ? "default" : node.name.text; return getNavigationBarItem( nodeName, diff --git a/tests/baselines/reference/anonymousClassExpression1.errors.txt b/tests/baselines/reference/anonymousClassExpression1.errors.txt new file mode 100644 index 0000000000..db4c5b4ce3 --- /dev/null +++ b/tests/baselines/reference/anonymousClassExpression1.errors.txt @@ -0,0 +1,9 @@ +tests/cases/compiler/anonymousClassExpression1.ts(2,19): error TS9003: 'class' expressions are not currently supported. + + +==== tests/cases/compiler/anonymousClassExpression1.ts (1 errors) ==== + function f() { + return typeof class {} === "function"; + ~~~~~ +!!! error TS9003: 'class' expressions are not currently supported. + } \ No newline at end of file diff --git a/tests/baselines/reference/anonymousClassExpression1.js b/tests/baselines/reference/anonymousClassExpression1.js new file mode 100644 index 0000000000..78cf5b05c5 --- /dev/null +++ b/tests/baselines/reference/anonymousClassExpression1.js @@ -0,0 +1,13 @@ +//// [anonymousClassExpression1.ts] +function f() { + return typeof class {} === "function"; +} + +//// [anonymousClassExpression1.js] +function f() { + return typeof (function () { + function default_1() { + } + return default_1; + })() === "function"; +} diff --git a/tests/baselines/reference/classDeclarationBlockScoping1.errors.txt b/tests/baselines/reference/classDeclarationBlockScoping1.errors.txt new file mode 100644 index 0000000000..4f15007bb2 --- /dev/null +++ b/tests/baselines/reference/classDeclarationBlockScoping1.errors.txt @@ -0,0 +1,13 @@ +tests/cases/compiler/classDeclarationBlockScoping1.ts(5,11): error TS9004: 'class' declarations are only supported directly inside a module or as a top level declaration. + + +==== tests/cases/compiler/classDeclarationBlockScoping1.ts (1 errors) ==== + class C { + } + + { + class C { + ~ +!!! error TS9004: 'class' declarations are only supported directly inside a module or as a top level declaration. + } + } \ No newline at end of file diff --git a/tests/baselines/reference/classDeclarationBlockScoping1.js b/tests/baselines/reference/classDeclarationBlockScoping1.js new file mode 100644 index 0000000000..717c2f788c --- /dev/null +++ b/tests/baselines/reference/classDeclarationBlockScoping1.js @@ -0,0 +1,22 @@ +//// [classDeclarationBlockScoping1.ts] +class C { +} + +{ + class C { + } +} + +//// [classDeclarationBlockScoping1.js] +var C = (function () { + function C() { + } + return C; +})(); +{ + var C = (function () { + function C() { + } + return C; + })(); +} diff --git a/tests/baselines/reference/classDeclarationBlockScoping2.errors.txt b/tests/baselines/reference/classDeclarationBlockScoping2.errors.txt new file mode 100644 index 0000000000..2a9885e110 --- /dev/null +++ b/tests/baselines/reference/classDeclarationBlockScoping2.errors.txt @@ -0,0 +1,18 @@ +tests/cases/compiler/classDeclarationBlockScoping2.ts(2,11): error TS9004: 'class' declarations are only supported directly inside a module or as a top level declaration. +tests/cases/compiler/classDeclarationBlockScoping2.ts(5,15): error TS9004: 'class' declarations are only supported directly inside a module or as a top level declaration. + + +==== tests/cases/compiler/classDeclarationBlockScoping2.ts (2 errors) ==== + function f() { + class C {} + ~ +!!! error TS9004: 'class' declarations are only supported directly inside a module or as a top level declaration. + var c1 = C; + { + class C {} + ~ +!!! error TS9004: 'class' declarations are only supported directly inside a module or as a top level declaration. + var c2 = C; + } + return C === c1; + } \ No newline at end of file diff --git a/tests/baselines/reference/classDeclarationBlockScoping2.js b/tests/baselines/reference/classDeclarationBlockScoping2.js new file mode 100644 index 0000000000..9e46807711 --- /dev/null +++ b/tests/baselines/reference/classDeclarationBlockScoping2.js @@ -0,0 +1,29 @@ +//// [classDeclarationBlockScoping2.ts] +function f() { + class C {} + var c1 = C; + { + class C {} + var c2 = C; + } + return C === c1; +} + +//// [classDeclarationBlockScoping2.js] +function f() { + var C = (function () { + function C() { + } + return C; + })(); + var c1 = C; + { + var C = (function () { + function C() { + } + return C; + })(); + var c2 = C; + } + return C === c1; +} diff --git a/tests/baselines/reference/classWithPredefinedTypesAsNames2.errors.txt b/tests/baselines/reference/classWithPredefinedTypesAsNames2.errors.txt index 73cb373180..84c258b550 100644 --- a/tests/baselines/reference/classWithPredefinedTypesAsNames2.errors.txt +++ b/tests/baselines/reference/classWithPredefinedTypesAsNames2.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/classes/classDeclarations/classWithPredefinedTypesAsNames2.ts(3,7): error TS1003: Identifier expected. +tests/cases/conformance/classes/classDeclarations/classWithPredefinedTypesAsNames2.ts(3,7): error TS1005: '{' expected. ==== tests/cases/conformance/classes/classDeclarations/classWithPredefinedTypesAsNames2.ts (1 errors) ==== @@ -6,4 +6,4 @@ tests/cases/conformance/classes/classDeclarations/classWithPredefinedTypesAsName class void {} ~~~~ -!!! error TS1003: Identifier expected. \ No newline at end of file +!!! error TS1005: '{' expected. \ No newline at end of file diff --git a/tests/baselines/reference/classWithPredefinedTypesAsNames2.js b/tests/baselines/reference/classWithPredefinedTypesAsNames2.js index a47adcbe32..91ff735acc 100644 --- a/tests/baselines/reference/classWithPredefinedTypesAsNames2.js +++ b/tests/baselines/reference/classWithPredefinedTypesAsNames2.js @@ -5,9 +5,9 @@ class void {} //// [classWithPredefinedTypesAsNames2.js] // classes cannot use predefined types as names -var = (function () { - function () { +var default_1 = (function () { + function default_1() { } - return ; + return default_1; })(); void {}; diff --git a/tests/baselines/reference/externModule.errors.txt b/tests/baselines/reference/externModule.errors.txt index d16c71ab05..8d4126350c 100644 --- a/tests/baselines/reference/externModule.errors.txt +++ b/tests/baselines/reference/externModule.errors.txt @@ -8,9 +8,13 @@ tests/cases/compiler/externModule.ts(18,6): error TS2390: Constructor implementa tests/cases/compiler/externModule.ts(20,13): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/compiler/externModule.ts(26,13): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/compiler/externModule.ts(28,13): error TS2391: Function implementation is missing or not immediately following the declaration. +tests/cases/compiler/externModule.ts(32,11): error TS2304: Cannot find name 'XDate'. +tests/cases/compiler/externModule.ts(34,7): error TS2304: Cannot find name 'XDate'. +tests/cases/compiler/externModule.ts(36,7): error TS2304: Cannot find name 'XDate'. +tests/cases/compiler/externModule.ts(37,3): error TS2304: Cannot find name 'XDate'. -==== tests/cases/compiler/externModule.ts (10 errors) ==== +==== tests/cases/compiler/externModule.ts (14 errors) ==== declare module { ~~~~~~~ !!! error TS2304: Cannot find name 'declare'. @@ -63,10 +67,18 @@ tests/cases/compiler/externModule.ts(28,13): error TS2391: Function implementati } var d=new XDate(); + ~~~~~ +!!! error TS2304: Cannot find name 'XDate'. d.getDay(); d=new XDate(1978,2); + ~~~~~ +!!! error TS2304: Cannot find name 'XDate'. d.getXDate(); var n=XDate.parse("3/2/2004"); + ~~~~~ +!!! error TS2304: Cannot find name 'XDate'. n=XDate.UTC(1964,2,1); + ~~~~~ +!!! error TS2304: Cannot find name 'XDate'. \ No newline at end of file diff --git a/tests/baselines/reference/objectTypesWithPredefinedTypesAsName2.errors.txt b/tests/baselines/reference/objectTypesWithPredefinedTypesAsName2.errors.txt index 32a693abdc..f2dbd67230 100644 --- a/tests/baselines/reference/objectTypesWithPredefinedTypesAsName2.errors.txt +++ b/tests/baselines/reference/objectTypesWithPredefinedTypesAsName2.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/types/specifyingTypes/predefinedTypes/objectTypesWithPredefinedTypesAsName2.ts(3,7): error TS1003: Identifier expected. +tests/cases/conformance/types/specifyingTypes/predefinedTypes/objectTypesWithPredefinedTypesAsName2.ts(3,7): error TS1005: '{' expected. ==== tests/cases/conformance/types/specifyingTypes/predefinedTypes/objectTypesWithPredefinedTypesAsName2.ts (1 errors) ==== @@ -6,4 +6,4 @@ tests/cases/conformance/types/specifyingTypes/predefinedTypes/objectTypesWithPre class void {} // parse error unlike the others ~~~~ -!!! error TS1003: Identifier expected. \ No newline at end of file +!!! error TS1005: '{' expected. \ No newline at end of file diff --git a/tests/baselines/reference/objectTypesWithPredefinedTypesAsName2.js b/tests/baselines/reference/objectTypesWithPredefinedTypesAsName2.js index b47901b2f0..974744f187 100644 --- a/tests/baselines/reference/objectTypesWithPredefinedTypesAsName2.js +++ b/tests/baselines/reference/objectTypesWithPredefinedTypesAsName2.js @@ -5,9 +5,9 @@ class void {} // parse error unlike the others //// [objectTypesWithPredefinedTypesAsName2.js] // it is an error to use a predefined type as a type name -var = (function () { - function () { +var default_1 = (function () { + function default_1() { } - return ; + return default_1; })(); void {}; // parse error unlike the others diff --git a/tests/baselines/reference/parserInvalidIdentifiersInVariableStatements1.errors.txt b/tests/baselines/reference/parserInvalidIdentifiersInVariableStatements1.errors.txt index 35b279b443..d7245fc708 100644 --- a/tests/baselines/reference/parserInvalidIdentifiersInVariableStatements1.errors.txt +++ b/tests/baselines/reference/parserInvalidIdentifiersInVariableStatements1.errors.txt @@ -1,6 +1,6 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/VariableLists/parserInvalidIdentifiersInVariableStatements1.ts(1,5): error TS1134: Variable declaration expected. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/VariableLists/parserInvalidIdentifiersInVariableStatements1.ts(3,5): error TS1134: Variable declaration expected. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/VariableLists/parserInvalidIdentifiersInVariableStatements1.ts(3,10): error TS1003: Identifier expected. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/VariableLists/parserInvalidIdentifiersInVariableStatements1.ts(3,10): error TS1005: '{' expected. ==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/VariableLists/parserInvalidIdentifiersInVariableStatements1.ts (3 errors) ==== @@ -12,6 +12,6 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/VariableLists/parserInv ~~~~~ !!! error TS1134: Variable declaration expected. ~ -!!! error TS1003: Identifier expected. +!!! error TS1005: '{' expected. var bar; \ No newline at end of file diff --git a/tests/baselines/reference/parserInvalidIdentifiersInVariableStatements1.js b/tests/baselines/reference/parserInvalidIdentifiersInVariableStatements1.js index 422b012246..e6b9c9fa1b 100644 --- a/tests/baselines/reference/parserInvalidIdentifiersInVariableStatements1.js +++ b/tests/baselines/reference/parserInvalidIdentifiersInVariableStatements1.js @@ -9,10 +9,10 @@ var bar; var ; var foo; var ; -var = (function () { - function () { +var default_1 = (function () { + function default_1() { } - return ; + return default_1; })(); ; var bar; diff --git a/tests/cases/compiler/anonymousClassExpression1.ts b/tests/cases/compiler/anonymousClassExpression1.ts new file mode 100644 index 0000000000..594ac09251 --- /dev/null +++ b/tests/cases/compiler/anonymousClassExpression1.ts @@ -0,0 +1,3 @@ +function f() { + return typeof class {} === "function"; +} \ No newline at end of file diff --git a/tests/cases/compiler/classDeclarationBlockScoping1.ts b/tests/cases/compiler/classDeclarationBlockScoping1.ts new file mode 100644 index 0000000000..b6012f785b --- /dev/null +++ b/tests/cases/compiler/classDeclarationBlockScoping1.ts @@ -0,0 +1,7 @@ +class C { +} + +{ + class C { + } +} \ No newline at end of file diff --git a/tests/cases/compiler/classDeclarationBlockScoping2.ts b/tests/cases/compiler/classDeclarationBlockScoping2.ts new file mode 100644 index 0000000000..2a0c4c1213 --- /dev/null +++ b/tests/cases/compiler/classDeclarationBlockScoping2.ts @@ -0,0 +1,9 @@ +function f() { + class C {} + var c1 = C; + { + class C {} + var c2 = C; + } + return C === c1; +} \ No newline at end of file diff --git a/tests/cases/fourslash/scriptLexicalStructureItems2.ts b/tests/cases/fourslash/scriptLexicalStructureItems2.ts index 7022c082ce..3b94260ddb 100644 --- a/tests/cases/fourslash/scriptLexicalStructureItems2.ts +++ b/tests/cases/fourslash/scriptLexicalStructureItems2.ts @@ -8,5 +8,5 @@ edit.insertLine("module A"); edit.insert("export class "); // should not crash -verify.getScriptLexicalStructureListCount(1); +verify.getScriptLexicalStructureListCount(2); diff --git a/tests/cases/fourslash/scriptLexicalStructureMissingName2.ts b/tests/cases/fourslash/scriptLexicalStructureMissingName2.ts index b805427ff6..bf0dc03899 100644 --- a/tests/cases/fourslash/scriptLexicalStructureMissingName2.ts +++ b/tests/cases/fourslash/scriptLexicalStructureMissingName2.ts @@ -8,4 +8,4 @@ // The class is unnamed, so its method is not included either. -verify.getScriptLexicalStructureListCount(0); +verify.getScriptLexicalStructureListCount(2);