From e4ea5ef1f94f1c3554d1dfb16121a15516bdab39 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 16 Jul 2014 14:18:33 -0700 Subject: [PATCH] Fix for 954635: Clodule declaration ordering Fix for 955714: Fundule declaration ordering --- src/compiler/checker.ts | 24 ++++++++++- .../diagnosticInformationMap.generated.ts | 2 + src/compiler/diagnosticMessages.json | 8 ++++ ...ModuleWithSameNameAndCommonRoot.errors.txt | 43 +++++++++++++++++++ ...ModuleWithSameNameAndCommonRoot.errors.txt | 6 ++- ...dClassWithSameNameAndCommonRoot.errors.txt | 38 ++++++++++++++++ ...nctionWithSameNameAndCommonRoot.errors.txt | 36 ++++++++++++++++ .../augmentedTypesModules.errors.txt | 8 +++- .../augmentedTypesModules2.errors.txt | 35 +++++++++++++++ .../augmentedTypesModules3.errors.txt | 9 ++++ .../cloduleSplitAcrossFiles.errors.txt | 12 ++++++ .../funduleSplitAcrossFiles.errors.txt | 12 ++++++ .../reference/invalidNestedModules.errors.txt | 9 +++- .../reference/nameCollisions.errors.txt | 6 ++- 14 files changed, 243 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/ClassAndModuleWithSameNameAndCommonRoot.errors.txt create mode 100644 tests/baselines/reference/ModuleAndClassWithSameNameAndCommonRoot.errors.txt create mode 100644 tests/baselines/reference/ModuleAndFunctionWithSameNameAndCommonRoot.errors.txt create mode 100644 tests/baselines/reference/augmentedTypesModules2.errors.txt create mode 100644 tests/baselines/reference/augmentedTypesModules3.errors.txt create mode 100644 tests/baselines/reference/cloduleSplitAcrossFiles.errors.txt create mode 100644 tests/baselines/reference/funduleSplitAcrossFiles.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5d76a3b127f..339f5f9a5de 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5317,8 +5317,31 @@ module ts { } } + function getClassOrFunctionBodyDeclaration(symbol: Symbol): Declaration { + var declarations = symbol.declarations; + for (var i = 0; i < declarations.length; i++) { + var declaration = declarations[i]; + if ((declaration.kind === SyntaxKind.ClassDeclaration || (declaration.kind === SyntaxKind.FunctionDeclaration && (declaration).body)) && !isInAmbientContext(declaration)) { + return declaration; + } + } + // Return undefined + } + function checkModuleDeclaration(node: ModuleDeclaration) { checkDeclarationModifiers(node); + var symbol = getSymbolOfNode(node); + if (symbol.flags & SymbolFlags.ValueModule && symbol.declarations.length > 1 && !isInAmbientContext(node)) { + var classOrFunc = getClassOrFunctionBodyDeclaration(symbol); + if (classOrFunc) { + if (getSourceFileOfNode(node) !== getSourceFileOfNode(classOrFunc)) { + error(node, Diagnostics.Module_declaration_cannot_be_in_different_file_from_class_or_function_with_which_it_is_merged); + } + else if (node.pos < classOrFunc.pos) { + error(node, Diagnostics.Module_declaration_cannot_be_located_prior_to_class_or_function_with_which_it_is_merged); + } + } + } if (node.name.kind === SyntaxKind.StringLiteral) { if (node.parent.kind !== SyntaxKind.SourceFile || node.parent.flags & NodeFlags.ExternalModule) { error(node, Diagnostics.Ambient_external_modules_cannot_be_nested_in_other_modules); @@ -5326,7 +5349,6 @@ module ts { if (isExternalModuleNameRelative(node.name.text)) { error(node, Diagnostics.Ambient_external_module_declaration_cannot_specify_relative_module_name); } - var symbol = getSymbolOfNode(node); } checkSourceElement(node.body); } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 59bfe4a60f6..13777088378 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -279,6 +279,8 @@ module ts { Interface_0_incorrectly_extends_interface_1: { code: -9999999, category: DiagnosticCategory.Error, key: "Interface '{0}' incorrectly extends interface '{1}'." }, Ambient_external_modules_cannot_be_nested_in_other_modules: { code: -9999999, category: DiagnosticCategory.Error, key: "Ambient external modules cannot be nested in other modules." }, Import_declarations_in_an_internal_module_cannot_reference_an_external_module: { code: -9999999, category: DiagnosticCategory.Error, key: "Import declarations in an internal module cannot reference an external module." }, + Module_declaration_cannot_be_in_different_file_from_class_or_function_with_which_it_is_merged: { code: -9999999, category: DiagnosticCategory.Error, key: "Module declaration cannot be in different file from class or function with which it is merged" }, + Module_declaration_cannot_be_located_prior_to_class_or_function_with_which_it_is_merged: { code: -9999999, category: DiagnosticCategory.Error, key: "Module declaration cannot be located prior to class or function with which it is merged" }, Cannot_compile_external_modules_unless_the_module_flag_is_provided: { code: -9999999, category: DiagnosticCategory.Error, key: "Cannot compile external modules unless the '--module' flag is provided." }, Import_declaration_conflicts_with_local_declaration_of_0: { code: -9999999, category: DiagnosticCategory.Error, key: "Import declaration conflicts with local declaration of '{0}'" }, Filename_0_differs_from_already_included_filename_1_only_in_casing: { code: -9999999, category: DiagnosticCategory.Error, key: "Filename '{0}' differs from already included filename '{1}' only in casing" }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index e3c54b96e8f..91611157cc3 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1140,6 +1140,14 @@ "category": "Error", "code": -9999999 }, + "Module declaration cannot be in different file from class or function with which it is merged": { + "category": "Error", + "code": -9999999 + }, + "Module declaration cannot be located prior to class or function with which it is merged": { + "category": "Error", + "code": -9999999 + }, "Cannot compile external modules unless the '--module' flag is provided.": { "category": "Error", "code": -9999999 diff --git a/tests/baselines/reference/ClassAndModuleWithSameNameAndCommonRoot.errors.txt b/tests/baselines/reference/ClassAndModuleWithSameNameAndCommonRoot.errors.txt new file mode 100644 index 00000000000..6674f0311f1 --- /dev/null +++ b/tests/baselines/reference/ClassAndModuleWithSameNameAndCommonRoot.errors.txt @@ -0,0 +1,43 @@ +==== tests/cases/conformance/internalModules/DeclarationMerging/class.ts (0 errors) ==== + module X.Y { + export class Point { + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } + x: number; + y: number; + } + } + +==== tests/cases/conformance/internalModules/DeclarationMerging/module.ts (1 errors) ==== + module X.Y { + export module Point { + ~~~~~~~~~~~~~~~~~~~~~ + export var Origin = new Point(0, 0); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + } + ~~~~~ +!!! Module declaration cannot be in different file from class or function with which it is merged + } + +==== tests/cases/conformance/internalModules/DeclarationMerging/test.ts (0 errors) ==== + //var cl: { x: number; y: number; } + var cl = new X.Y.Point(1,1); + var cl = X.Y.Point.Origin; // error not expected here same as bug 83996 ? + + +==== tests/cases/conformance/internalModules/DeclarationMerging/simple.ts (0 errors) ==== + class A { + id: string; + } + + module A { + export var Instance = new A(); + } + + // ensure merging works as expected + var a = A.Instance; + var a = new A(); + var a: { id: string }; + \ No newline at end of file diff --git a/tests/baselines/reference/FunctionAndModuleWithSameNameAndCommonRoot.errors.txt b/tests/baselines/reference/FunctionAndModuleWithSameNameAndCommonRoot.errors.txt index f2168a9056f..8c1c451389a 100644 --- a/tests/baselines/reference/FunctionAndModuleWithSameNameAndCommonRoot.errors.txt +++ b/tests/baselines/reference/FunctionAndModuleWithSameNameAndCommonRoot.errors.txt @@ -5,11 +5,15 @@ } } -==== tests/cases/conformance/internalModules/DeclarationMerging/module.ts (0 errors) ==== +==== tests/cases/conformance/internalModules/DeclarationMerging/module.ts (1 errors) ==== module A { export module Point { + ~~~~~~~~~~~~~~~~~~~~~ export var Origin = { x: 0, y: 0 }; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } + ~~~~~ +!!! Module declaration cannot be in different file from class or function with which it is merged } ==== tests/cases/conformance/internalModules/DeclarationMerging/test.ts (1 errors) ==== diff --git a/tests/baselines/reference/ModuleAndClassWithSameNameAndCommonRoot.errors.txt b/tests/baselines/reference/ModuleAndClassWithSameNameAndCommonRoot.errors.txt new file mode 100644 index 00000000000..89f4449b95e --- /dev/null +++ b/tests/baselines/reference/ModuleAndClassWithSameNameAndCommonRoot.errors.txt @@ -0,0 +1,38 @@ +==== tests/cases/conformance/internalModules/DeclarationMerging/module.ts (1 errors) ==== + module X.Y { + export module Point { + ~~~~~~~~~~~~~~~~~~~~~ + export var Origin = new Point(0, 0); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + } + ~~~~~ +!!! Module declaration cannot be in different file from class or function with which it is merged + } + +==== tests/cases/conformance/internalModules/DeclarationMerging/classPoint.ts (0 errors) ==== + module X.Y { + // duplicate identifier + export class Point { + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } + x: number; + y: number; + } + } + +==== tests/cases/conformance/internalModules/DeclarationMerging/simple.ts (1 errors) ==== + module A { + ~~~~~~~~~~ + export var Instance = new A(); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + } + ~ +!!! Module declaration cannot be located prior to class or function with which it is merged + + // duplicate identifier + class A { + id: string; + } + \ No newline at end of file diff --git a/tests/baselines/reference/ModuleAndFunctionWithSameNameAndCommonRoot.errors.txt b/tests/baselines/reference/ModuleAndFunctionWithSameNameAndCommonRoot.errors.txt new file mode 100644 index 00000000000..2baeeccbffb --- /dev/null +++ b/tests/baselines/reference/ModuleAndFunctionWithSameNameAndCommonRoot.errors.txt @@ -0,0 +1,36 @@ +==== tests/cases/conformance/internalModules/DeclarationMerging/module.ts (1 errors) ==== + module A { + export module Point { + ~~~~~~~~~~~~~~~~~~~~~ + export var Origin = { x: 0, y: 0 }; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + } + ~~~~~ +!!! Module declaration cannot be in different file from class or function with which it is merged + } + +==== tests/cases/conformance/internalModules/DeclarationMerging/function.ts (0 errors) ==== + module A { + // duplicate identifier error + export function Point() { + return { x: 0, y: 0 }; + } + } + +==== tests/cases/conformance/internalModules/DeclarationMerging/simple.ts (1 errors) ==== + module B { + + export module Point { + ~~~~~~~~~~~~~~~~~~~~~ + export var Origin = { x: 0, y: 0 }; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + } + ~~~~~ +!!! Module declaration cannot be located prior to class or function with which it is merged + + // duplicate identifier error + export function Point() { + return { x: 0, y: 0 }; + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/augmentedTypesModules.errors.txt b/tests/baselines/reference/augmentedTypesModules.errors.txt index b33ee75570d..146b0641479 100644 --- a/tests/baselines/reference/augmentedTypesModules.errors.txt +++ b/tests/baselines/reference/augmentedTypesModules.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/compiler/augmentedTypesModules.ts (3 errors) ==== +==== tests/cases/compiler/augmentedTypesModules.ts (6 errors) ==== // module then var module m1 { } var m1 = 1; // Should be allowed @@ -30,9 +30,13 @@ function m2() { }; // ok since the module is not instantiated module m2a { var y = 2; } + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! Module declaration cannot be located prior to class or function with which it is merged function m2a() { }; // error since the module is instantiated module m2b { export var y = 2; } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! Module declaration cannot be located prior to class or function with which it is merged function m2b() { }; // error since the module is instantiated // should be errors to have function first @@ -56,6 +60,8 @@ class m3 { } // ok since the module is not instantiated module m3a { var y = 2; } + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! Module declaration cannot be located prior to class or function with which it is merged class m3a { foo() { } } // error, class isn't ambient or declared before the module class m3b { foo() { } } diff --git a/tests/baselines/reference/augmentedTypesModules2.errors.txt b/tests/baselines/reference/augmentedTypesModules2.errors.txt new file mode 100644 index 00000000000..30165cbc6dd --- /dev/null +++ b/tests/baselines/reference/augmentedTypesModules2.errors.txt @@ -0,0 +1,35 @@ +==== tests/cases/compiler/augmentedTypesModules2.ts (3 errors) ==== + // module then function + module m2 { } + function m2() { }; // ok since the module is not instantiated + + module m2a { var y = 2; } + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! Module declaration cannot be located prior to class or function with which it is merged + function m2a() { }; // error since the module is instantiated + + module m2b { export var y = 2; } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! Module declaration cannot be located prior to class or function with which it is merged + function m2b() { }; // error since the module is instantiated + + function m2c() { }; + module m2c { export var y = 2; } + + module m2cc { export var y = 2; } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! Module declaration cannot be located prior to class or function with which it is merged + function m2cc() { }; // error to have module first + + module m2d { } + declare function m2d(): void; + + declare function m2e(): void; + module m2e { } + + function m2f() { }; + module m2f { export interface I { foo(): void } } + + function m2g() { }; + module m2g { export class C { foo() { } } } + \ No newline at end of file diff --git a/tests/baselines/reference/augmentedTypesModules3.errors.txt b/tests/baselines/reference/augmentedTypesModules3.errors.txt new file mode 100644 index 00000000000..b2011b93734 --- /dev/null +++ b/tests/baselines/reference/augmentedTypesModules3.errors.txt @@ -0,0 +1,9 @@ +==== tests/cases/compiler/augmentedTypesModules3.ts (1 errors) ==== + //// module then class + module m3 { } + class m3 { } // ok since the module is not instantiated + + module m3a { var y = 2; } + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! Module declaration cannot be located prior to class or function with which it is merged + class m3a { foo() { } } // error, class isn't ambient or declared before the module \ No newline at end of file diff --git a/tests/baselines/reference/cloduleSplitAcrossFiles.errors.txt b/tests/baselines/reference/cloduleSplitAcrossFiles.errors.txt new file mode 100644 index 00000000000..c97f2e80103 --- /dev/null +++ b/tests/baselines/reference/cloduleSplitAcrossFiles.errors.txt @@ -0,0 +1,12 @@ +==== tests/cases/compiler/cloduleSplitAcrossFiles_class.ts (0 errors) ==== + class D { } + +==== tests/cases/compiler/cloduleSplitAcrossFiles_module.ts (1 errors) ==== + module D { + ~~~~~~~~~~ + export var y = "hi"; + ~~~~~~~~~~~~~~~~~~~~~~~~ + } + ~ +!!! Module declaration cannot be in different file from class or function with which it is merged + D.y; \ No newline at end of file diff --git a/tests/baselines/reference/funduleSplitAcrossFiles.errors.txt b/tests/baselines/reference/funduleSplitAcrossFiles.errors.txt new file mode 100644 index 00000000000..f98c41022c1 --- /dev/null +++ b/tests/baselines/reference/funduleSplitAcrossFiles.errors.txt @@ -0,0 +1,12 @@ +==== tests/cases/compiler/funduleSplitAcrossFiles_function.ts (0 errors) ==== + function D() { } + +==== tests/cases/compiler/funduleSplitAcrossFiles_module.ts (1 errors) ==== + module D { + ~~~~~~~~~~ + export var y = "hi"; + ~~~~~~~~~~~~~~~~~~~~~~~~ + } + ~ +!!! Module declaration cannot be in different file from class or function with which it is merged + D.y; \ No newline at end of file diff --git a/tests/baselines/reference/invalidNestedModules.errors.txt b/tests/baselines/reference/invalidNestedModules.errors.txt index 73a9d1e8f7f..4426e9871ce 100644 --- a/tests/baselines/reference/invalidNestedModules.errors.txt +++ b/tests/baselines/reference/invalidNestedModules.errors.txt @@ -1,10 +1,17 @@ -==== tests/cases/conformance/internalModules/moduleDeclarations/invalidNestedModules.ts (1 errors) ==== +==== tests/cases/conformance/internalModules/moduleDeclarations/invalidNestedModules.ts (2 errors) ==== module A.B.C { + ~~~ export class Point { + ~~~~~~~~~~~~~~~~~~~~~~~~ x: number; + ~~~~~~~~~~~~~~~~~~ y: number; + ~~~~~~~~~~~~~~~~~~ } + ~~~~~ } + ~ +!!! Module declaration cannot be located prior to class or function with which it is merged module A { export module B { diff --git a/tests/baselines/reference/nameCollisions.errors.txt b/tests/baselines/reference/nameCollisions.errors.txt index 21246658bc2..1982f6450d1 100644 --- a/tests/baselines/reference/nameCollisions.errors.txt +++ b/tests/baselines/reference/nameCollisions.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/compiler/nameCollisions.ts (8 errors) ==== +==== tests/cases/compiler/nameCollisions.ts (9 errors) ==== module T { var x = 2; @@ -18,8 +18,12 @@ !!! Duplicate identifier 'z'. module y { + ~~~~~~~~~~ var b; + ~~~~~~~~~~~~~~ } + ~~~~~ +!!! Module declaration cannot be located prior to class or function with which it is merged class y { } // error