diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7f04f629bd..c6c339e37a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4941,28 +4941,34 @@ module ts { } } + // run the check only for the first declaration in the list if (getDeclarationOfKind(symbol, node.kind) !== node) { return; } // we use SymbolFlags.ExportValue, SymbolFlags.ExportType and SymbolFlags.ExportNamespace // to denote disjoint declarationSpaces (without making new enum type). - var declarationSpaces: SymbolFlags = 0; - var hasExport: boolean; - - var declarations = symbol.declarations; - for (var i = 0, len = declarations.length; i < len; ++i) { - var currentDeclarationSpaces = getDeclarationSpaces(declarations[i]); - var currentDeclarationHasExport = (declarations[i].flags & NodeFlags.Export) !== 0; - if (declarationSpaces & currentDeclarationSpaces) { - if (hasExport !== undefined) { - if (hasExport !== currentDeclarationHasExport) { - error(declarations[i].name, Diagnostics.All_declarations_of_merged_declaration_0_must_be_exported_or_not_exported, symbolToString(symbol)); - } - } + var exportedDeclarationSpaces: SymbolFlags = 0; + var nonExportedDeclarationSpaces: SymbolFlags = 0; + forEach(symbol.declarations, d => { + var declarationSpaces = getDeclarationSpaces(d); + if (d.flags & NodeFlags.Export) { + exportedDeclarationSpaces |= declarationSpaces; } - hasExport = hasExport || currentDeclarationHasExport; - declarationSpaces |= currentDeclarationSpaces; + else { + nonExportedDeclarationSpaces |= declarationSpaces; + } + }); + + var commonDeclarationSpace = exportedDeclarationSpaces & nonExportedDeclarationSpaces + + if (commonDeclarationSpace) { + // declaration spaces for exported and non-exported declarations intersect + forEach(symbol.declarations, d => { + if (getDeclarationSpaces(d) & commonDeclarationSpace) { + error(d.name, Diagnostics.Individual_declarations_in_a_merged_declaration_0_must_be_all_exported_or_all_local, identifierToString(d.name)); + } + }); } function getDeclarationSpaces(d: Declaration): SymbolFlags { @@ -4977,8 +4983,10 @@ module ts { case SyntaxKind.EnumDeclaration: return SymbolFlags.ExportType | SymbolFlags.ExportValue; case SyntaxKind.ImportDeclaration: + var result: SymbolFlags = 0; var target = resolveImport(getSymbolOfNode(d)); - return target.flags & SymbolFlags.Export; + forEach(target.declarations, d => { result |= getDeclarationSpaces(d); } ) + return result; default: return SymbolFlags.ExportValue; } @@ -5000,10 +5008,10 @@ module ts { checkFunctionOrConstructorSymbol(localSymbol); } - if (symbol !== localSymbol) { - // here we'll check exported side of the symbol - Debug.assert(symbol.parent); + if (symbol.parent) { + // run check once for the first declaration if (getDeclarationOfKind(symbol, node.kind) === node) { + // run check on export symbol to check that modifiers agree across all exported declarations checkFunctionOrConstructorSymbol(symbol); } } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 903dda0ce6..11809aca06 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -137,7 +137,7 @@ module ts { A_signature_with_an_implementation_cannot_use_a_string_literal_type: { code: 2163, category: DiagnosticCategory.Error, key: "A signature with an implementation cannot use a string literal type." }, Interface_0_cannot_simultaneously_extend_types_1_and_2_Colon: { code: 2189, category: DiagnosticCategory.Error, key: "Interface '{0}' cannot simultaneously extend types '{1}' and '{2}':" }, Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it: { code: 2190, category: DiagnosticCategory.Error, key: "Initializer of parameter '{0}' cannot reference identifier '{1}' declared after it." }, - All_declarations_of_merged_declaration_0_must_be_exported_or_not_exported: { code: 2192, category: DiagnosticCategory.Error, key: "All declarations of merged declaration '{0}' must be exported or not exported." }, + Individual_declarations_in_a_merged_declaration_0_must_be_all_exported_or_all_local: { code: 2192, category: DiagnosticCategory.Error, key: "Individual declarations in a merged declaration {0} must be all exported or all local." }, super_cannot_be_referenced_in_constructor_arguments: { code: 2193, category: DiagnosticCategory.Error, key: "'super' cannot be referenced in constructor arguments." }, Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class: { code: 2194, category: DiagnosticCategory.Error, key: "Return type of constructor signature must be assignable to the instance type of the class" }, Ambient_external_module_declaration_cannot_specify_relative_module_name: { code: 2196, category: DiagnosticCategory.Error, key: "Ambient external module declaration cannot specify relative module name." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1b99fdd5f9..d3a34d2733 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -540,7 +540,7 @@ "category": "Error", "code": 2190 }, - "All declarations of merged declaration '{0}' must be exported or not exported.": { + "Individual declarations in a merged declaration {0} must be all exported or all local.": { "category": "Error", "code": 2192 }, diff --git a/tests/baselines/reference/anonymousModules.errors.txt b/tests/baselines/reference/anonymousModules.errors.txt index 2663477cc3..9f07d99851 100644 --- a/tests/baselines/reference/anonymousModules.errors.txt +++ b/tests/baselines/reference/anonymousModules.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/compiler/anonymousModules.ts (12 errors) ==== +==== tests/cases/compiler/anonymousModules.ts (13 errors) ==== module { ~ !!! ';' expected. @@ -18,13 +18,15 @@ export var bar = 1; ~~~~~~ !!! Statement expected. + ~~~ +!!! Individual declarations in a merged declaration bar must be all exported or all local. } ~ !!! Declaration or statement expected. var bar = 2; ~~~ -!!! All declarations of merged declaration 'bar' must be exported or not exported. +!!! Individual declarations in a merged declaration bar must be all exported or all local. module { ~ diff --git a/tests/baselines/reference/duplicateSymbolsExportMatching.errors.txt b/tests/baselines/reference/duplicateSymbolsExportMatching.errors.txt index 1d712f9c5c..ba20d24b55 100644 --- a/tests/baselines/reference/duplicateSymbolsExportMatching.errors.txt +++ b/tests/baselines/reference/duplicateSymbolsExportMatching.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/compiler/duplicateSymbolsExportMatching.ts (9 errors) ==== +==== tests/cases/compiler/duplicateSymbolsExportMatching.ts (18 errors) ==== module M { export interface E { } interface I { } @@ -23,23 +23,29 @@ module N2 { interface I { } + ~ +!!! Individual declarations in a merged declaration I must be all exported or all local. export interface I { } // error ~ -!!! All declarations of merged declaration 'I' must be exported or not exported. +!!! Individual declarations in a merged declaration I must be all exported or all local. export interface E { } + ~ +!!! Individual declarations in a merged declaration E must be all exported or all local. interface E { } // error ~ -!!! All declarations of merged declaration 'E' must be exported or not exported. +!!! Individual declarations in a merged declaration E must be all exported or all local. } // Should report error only once for instantiated module module M { module inst { + ~~~~ +!!! Individual declarations in a merged declaration inst must be all exported or all local. var t; } export module inst { // one error ~~~~ -!!! All declarations of merged declaration 'inst' must be exported or not exported. +!!! Individual declarations in a merged declaration inst must be all exported or all local. var t; } } @@ -47,38 +53,50 @@ // Variables of the same / different type module M2 { var v: string; + ~ +!!! Individual declarations in a merged declaration v must be all exported or all local. export var v: string; // one error (visibility) ~ -!!! All declarations of merged declaration 'v' must be exported or not exported. +!!! Individual declarations in a merged declaration v must be all exported or all local. var w: number; + ~ +!!! Individual declarations in a merged declaration w must be all exported or all local. export var w: string; // two errors (visibility and type mismatch) ~ -!!! All declarations of merged declaration 'w' must be exported or not exported. +!!! Individual declarations in a merged declaration w must be all exported or all local. } module M { module F { ~ !!! A module declaration cannot be located prior to a class or function with which it is merged + ~ +!!! Individual declarations in a merged declaration F must be all exported or all local. var t; } export function F() { } // Only one error for duplicate identifier (don't consider visibility) ~ -!!! All declarations of merged declaration 'F' must be exported or not exported. +!!! Individual declarations in a merged declaration F must be all exported or all local. } module M { class C { } + ~ +!!! Individual declarations in a merged declaration C must be all exported or all local. module C { } + ~ +!!! Individual declarations in a merged declaration C must be all exported or all local. export module C { // Two visibility errors (one for the clodule symbol, and one for the merged container symbol) ~ -!!! All declarations of merged declaration 'C' must be exported or not exported. +!!! Individual declarations in a merged declaration C must be all exported or all local. var t; } } // Top level interface D { } + ~ +!!! Individual declarations in a merged declaration D must be all exported or all local. export interface D { } ~ -!!! All declarations of merged declaration 'D' must be exported or not exported. \ No newline at end of file +!!! Individual declarations in a merged declaration D must be all exported or all local. \ No newline at end of file diff --git a/tests/baselines/reference/mixedExports.js b/tests/baselines/reference/mixedExports.js new file mode 100644 index 0000000000..eb650667e8 --- /dev/null +++ b/tests/baselines/reference/mixedExports.js @@ -0,0 +1,14 @@ +//// [mixedExports.ts] +declare module M { + function foo(); + export function foo(); + function foo(); +} + +module A { + interface X {x} + export module X {} + interface X {y} +} + +//// [mixedExports.js] diff --git a/tests/baselines/reference/multivar.errors.txt b/tests/baselines/reference/multivar.errors.txt index 66db194234..0a1496f4a9 100644 --- a/tests/baselines/reference/multivar.errors.txt +++ b/tests/baselines/reference/multivar.errors.txt @@ -1,10 +1,12 @@ -==== tests/cases/compiler/multivar.ts (1 errors) ==== +==== tests/cases/compiler/multivar.ts (2 errors) ==== var a,b,c; var x=1,y=2,z=3; module m2 { export var a, b2: number = 10, b; + ~~ +!!! Individual declarations in a merged declaration b2 must be all exported or all local. var m1; var a2, b22: number = 10, b222; var m3; @@ -22,7 +24,7 @@ declare var d1, d2; var b2; ~~ -!!! All declarations of merged declaration 'b2' must be exported or not exported. +!!! Individual declarations in a merged declaration b2 must be all exported or all local. declare var v1; } diff --git a/tests/cases/compiler/mixedExports.ts b/tests/cases/compiler/mixedExports.ts new file mode 100644 index 0000000000..bad962c8e1 --- /dev/null +++ b/tests/cases/compiler/mixedExports.ts @@ -0,0 +1,11 @@ +declare module M { + function foo(); + export function foo(); + function foo(); +} + +module A { + interface X {x} + export module X {} + interface X {y} +} \ No newline at end of file