diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 665213dd6648d..e05363f46e715 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -415,8 +415,13 @@ module ts { } function getExportAssignmentSymbol(symbol: Symbol): Symbol { - if (!symbol.exportAssignSymbol) { - var exportInformation = collectExportInformationForSourceFileOrModule(symbol); + checkAndStoreTypeOfExportAssignmentSymbol(symbol); + return symbol.exportAssignSymbol === unknownSymbol ? undefined : symbol.exportAssignSymbol; + } + + function checkAndStoreTypeOfExportAssignmentSymbol(containerSymbol: Symbol): void { + if (!containerSymbol.exportAssignSymbol) { + var exportInformation = collectExportInformationForSourceFileOrModule(containerSymbol); if (exportInformation.exportAssignments.length) { if (exportInformation.exportAssignments.length > 1) { // TypeScript 1.0 spec (April 2014): 11.2.4 @@ -436,9 +441,8 @@ module ts { var exportSymbol = resolveName(node, node.exportName.text, meaning, Diagnostics.Cannot_find_name_0, identifierToString(node.exportName)); } } - symbol.exportAssignSymbol = exportSymbol || unknownSymbol; + containerSymbol.exportAssignSymbol = exportSymbol || unknownSymbol; } - return symbol.exportAssignSymbol === unknownSymbol ? undefined : symbol.exportAssignSymbol; } function collectExportInformationForSourceFileOrModule(symbol: Symbol) { @@ -504,8 +508,12 @@ module ts { var declarations = symbol.declarations; for (var i = 0; i < declarations.length; i++) { var declaration = declarations[i]; - if (declaration.kind === kind) return declaration; + if (declaration.kind === kind) { + return declaration; + } } + + return undefined; } function findConstructorDeclaration(node: ClassDeclaration): ConstructorDeclaration { @@ -922,6 +930,12 @@ module ts { function getTypeOfAccessors(symbol: Symbol): Type { var links = getSymbolLinks(symbol); + checkAndStoreTypeOfAccessors(symbol, links); + return links.type; + } + + function checkAndStoreTypeOfAccessors(symbol: Symbol, links?: SymbolLinks) { + links = links || getSymbolLinks(symbol); if (!links.type) { links.type = resolvingType; var getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); @@ -955,7 +969,6 @@ module ts { } } } - if (links.type === resolvingType) { links.type = type; @@ -964,7 +977,6 @@ module ts { else if (links.type === resolvingType) { links.type = anyType; } - return links.type; } function getTypeOfFuncClassEnumModule(symbol: Symbol): Type { @@ -4212,11 +4224,10 @@ module ts { checkSourceElement(node.body); var symbol = getSymbolOfNode(node); - var symbolLinks = getSymbolLinks(symbol); - var type = getTypeOfSymbol(symbol.parent); - if (!(symbolLinks.typeChecked)) { + var firstDeclaration = getDeclarationOfKind(symbol, node.kind); + // Only type check the symbol once + if (node === firstDeclaration) { checkFunctionOrConstructorSymbol(symbol); - symbolLinks.typeChecked = true; } // exit early in the case of signature - super checks are not relevant to them @@ -4335,6 +4346,7 @@ module ts { } checkFunctionDeclaration(node); + checkAndStoreTypeOfAccessors(getSymbolOfNode(node)); } function checkTypeReference(node: TypeReferenceNode) { @@ -4550,12 +4562,12 @@ module ts { function checkFunctionDeclaration(node: FunctionDeclaration) { checkDeclarationModifiers(node); checkSignatureDeclaration(node); + var symbol = getSymbolOfNode(node); - var symbolLinks = getSymbolLinks(symbol); - var type = getTypeOfSymbol(symbol); - if (!(symbolLinks.typeChecked)) { + var firstDeclaration = getDeclarationOfKind(symbol, node.kind); + // Only type check the symbol once + if (node === firstDeclaration) { checkFunctionOrConstructorSymbol(symbol); - symbolLinks.typeChecked = true; } checkSourceElement(node.body); @@ -5156,15 +5168,15 @@ module ts { checkNameIsReserved(node.name, Diagnostics.Interface_name_cannot_be_0); checkTypeParameters(node.typeParameters); var symbol = getSymbolOfNode(node); + var firstInterfaceDecl = getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration); if (symbol.declarations.length > 1) { - var firstInterfaceDecl = getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration); if (node !== firstInterfaceDecl && !areTypeParametersIdentical(firstInterfaceDecl.typeParameters, node.typeParameters)) { error(node.name, Diagnostics.All_declarations_of_an_interface_must_have_identical_type_parameters); } } - var links = getSymbolLinks(symbol); - if (!links.typeChecked) { + // Only check this symbol once + if (node === firstInterfaceDecl) { var type = getDeclaredTypeOfSymbol(symbol); // run subsequent checks only if first set succeeded if (checkInheritedPropertiesAreIdentical(type, node.name)) { @@ -5173,7 +5185,6 @@ module ts { }); checkIndexConstraints(type); } - links.typeChecked = true; } forEach(node.baseTypes, checkTypeReference); forEach(node.members, checkSourceElement); @@ -5237,11 +5248,6 @@ module ts { error(node, Diagnostics.Ambient_external_module_declaration_cannot_specify_relative_module_name); } var symbol = getSymbolOfNode(node); - var links = getSymbolLinks(symbol); - if (!links.typeChecked) { - getExportAssignmentSymbol(symbol); - links.typeChecked = true; - } } checkSourceElement(node.body); } @@ -5310,6 +5316,11 @@ module ts { if (container.kind === SyntaxKind.SourceFile) { checkModulesEnabled(node); } + else { + // In a module, the immediate parent will be a block, so climb up one more parent + container = container.parent; + } + checkAndStoreTypeOfExportAssignmentSymbol(getSymbolOfNode(container)); } function checkSourceElement(node: Node): void { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ef9a39dfe28b0..d635091b25ae1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -693,7 +693,6 @@ module ts { type?: Type; // Type of value symbol declaredType?: Type; // Type of class, interface, enum, or type parameter mapper?: TypeMapper; // Type mapper for instantiation alias - typeChecked?: boolean; // True if symbol has been type checked referenced?: boolean; // True if alias symbol has been referenced as a value } diff --git a/tests/baselines/reference/functionAndInterfaceWithSeparateErrors.errors.txt b/tests/baselines/reference/functionAndInterfaceWithSeparateErrors.errors.txt new file mode 100644 index 0000000000000..58936d29dbb2a --- /dev/null +++ b/tests/baselines/reference/functionAndInterfaceWithSeparateErrors.errors.txt @@ -0,0 +1,12 @@ +==== tests/cases/compiler/functionAndInterfaceWithSeparateErrors.ts (2 errors) ==== + function Foo(s: string); + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! Overload signature is not compatible with function implementation. + function Foo(n: number) { } + + interface Foo { + [s: string]: string; + prop: number; + ~~~~~~~~~~~~~ +!!! Property 'prop' of type 'number' is not assignable to string index type 'string'. + } \ No newline at end of file diff --git a/tests/baselines/reference/functionAndInterfaceWithSeparateErrors.js b/tests/baselines/reference/functionAndInterfaceWithSeparateErrors.js new file mode 100644 index 0000000000000..004e65d92afb1 --- /dev/null +++ b/tests/baselines/reference/functionAndInterfaceWithSeparateErrors.js @@ -0,0 +1,12 @@ +//// [functionAndInterfaceWithSeparateErrors.ts] +function Foo(s: string); +function Foo(n: number) { } + +interface Foo { + [s: string]: string; + prop: number; +} + +//// [functionAndInterfaceWithSeparateErrors.js] +function Foo(n) { +} diff --git a/tests/baselines/reference/parserExportAssignment5.errors.txt b/tests/baselines/reference/parserExportAssignment5.errors.txt index 01cd8392c059b..c72673ef86528 100644 --- a/tests/baselines/reference/parserExportAssignment5.errors.txt +++ b/tests/baselines/reference/parserExportAssignment5.errors.txt @@ -1,6 +1,8 @@ -==== tests/cases/conformance/parser/ecmascript5/ExportAssignments/parserExportAssignment5.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ExportAssignments/parserExportAssignment5.ts (2 errors) ==== module M { export = A; ~~~~~~~~~~~ !!! An export assignment cannot be used in an internal module. + ~~~~~~~~~~~ +!!! Cannot find name 'A'. } \ No newline at end of file diff --git a/tests/cases/compiler/functionAndInterfaceWithSeparateErrors.ts b/tests/cases/compiler/functionAndInterfaceWithSeparateErrors.ts new file mode 100644 index 0000000000000..771e0488450c4 --- /dev/null +++ b/tests/cases/compiler/functionAndInterfaceWithSeparateErrors.ts @@ -0,0 +1,7 @@ +function Foo(s: string); +function Foo(n: number) { } + +interface Foo { + [s: string]: string; + prop: number; +} \ No newline at end of file