diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5a01a421cea..61cf3298fd8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -454,18 +454,26 @@ module ts { } function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol { - return node.moduleReference.kind === SyntaxKind.ExternalModuleReference ? - resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node)) : - getSymbolOfPartOfRightHandSideOfImportEquals(node.moduleReference, node); + if (node.moduleReference.kind === SyntaxKind.ExternalModuleReference) { + var moduleSymbol = resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node)); + var exportAssignmentSymbol = moduleSymbol && getResolvedExportAssignmentSymbol(moduleSymbol); + return exportAssignmentSymbol || moduleSymbol; + } + return getSymbolOfPartOfRightHandSideOfImportEquals(node.moduleReference, node); } function getTargetOfImportClause(node: ImportClause): Symbol { - // TODO: Verify that returned symbol originates in "export default" statement - return resolveExternalModuleName(node, (node.parent).moduleSpecifier); + var moduleSymbol = resolveExternalModuleName(node, (node.parent).moduleSpecifier); + if (moduleSymbol) { + var exportAssignmentSymbol = getResolvedExportAssignmentSymbol(moduleSymbol); + if (!exportAssignmentSymbol) { + error(node.name, Diagnostics.External_module_0_has_no_default_export_or_export_assignment, symbolToString(moduleSymbol)); + } + return exportAssignmentSymbol; + } } function getTargetOfNamespaceImport(node: NamespaceImport): Symbol { - // TODO: Verify that returned symbol does not originate in "export default" statement return resolveExternalModuleName(node, (node.parent.parent).moduleSpecifier); } @@ -598,7 +606,7 @@ module ts { if (!isRelative) { var symbol = getSymbol(globals, '"' + moduleName + '"', SymbolFlags.ValueModule); if (symbol) { - return getResolvedExportSymbol(symbol); + return symbol; } } while (true) { @@ -611,7 +619,7 @@ module ts { } if (sourceFile) { if (sourceFile.symbol) { - return getResolvedExportSymbol(sourceFile.symbol); + return sourceFile.symbol; } error(moduleReferenceLiteral, Diagnostics.File_0_is_not_an_external_module, sourceFile.fileName); return; @@ -619,7 +627,7 @@ module ts { error(moduleReferenceLiteral, Diagnostics.Cannot_find_external_module_0, moduleName); } - function getResolvedExportSymbol(moduleSymbol: Symbol): Symbol { + function getResolvedExportAssignmentSymbol(moduleSymbol: Symbol): Symbol { var symbol = getExportAssignmentSymbol(moduleSymbol); if (symbol) { if (symbol.flags & (SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace)) { @@ -629,18 +637,16 @@ module ts { return resolveImport(symbol); } } - return moduleSymbol; } function getExportAssignmentSymbol(symbol: Symbol): Symbol { checkTypeOfExportAssignmentSymbol(symbol); - var symbolLinks = getSymbolLinks(symbol); - return symbolLinks.exportAssignSymbol === unknownSymbol ? undefined : symbolLinks.exportAssignSymbol; + return getSymbolLinks(symbol).exportAssignSymbol; } function checkTypeOfExportAssignmentSymbol(containerSymbol: Symbol): void { var symbolLinks = getSymbolLinks(containerSymbol); - if (!symbolLinks.exportAssignSymbol) { + if (!symbolLinks.exportAssignChecked) { var exportInformation = collectExportInformationForSourceFileOrModule(containerSymbol); if (exportInformation.exportAssignments.length) { if (exportInformation.exportAssignments.length > 1) { @@ -660,8 +666,9 @@ module ts { var meaning = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace; var exportSymbol = resolveName(node, node.exportName.text, meaning, Diagnostics.Cannot_find_name_0, node.exportName); } + symbolLinks.exportAssignSymbol = exportSymbol || unknownSymbol; } - symbolLinks.exportAssignSymbol = exportSymbol || unknownSymbol; + symbolLinks.exportAssignChecked = true; } } @@ -9284,13 +9291,12 @@ module ts { for (var i = 0, n = statements.length; i < n; i++) { var statement = statements[i]; + // TODO: AndersH: No reason to do a separate pass over the statements for this check, we should + // just fold it into checkExportAssignment. if (statement.kind === SyntaxKind.ExportAssignment) { // Export assignments are not allowed in an internal module grammarErrorOnNode(statement, Diagnostics.An_export_assignment_cannot_be_used_in_an_internal_module); } - else if (isExternalModuleImportEqualsDeclaration(statement)) { - grammarErrorOnNode(getExternalModuleImportEqualsDeclarationExpression(statement), Diagnostics.Import_declarations_in_an_internal_module_cannot_reference_an_external_module); - } } } } @@ -10197,7 +10203,7 @@ module ts { function getExportAssignmentName(node: SourceFile): string { var symbol = getExportAssignmentSymbol(getSymbolOfNode(node)); - return symbol && symbolIsValue(symbol) && !isConstEnumSymbol(symbol) ? symbolToString(symbol): undefined; + return symbol && symbol !== unknownSymbol && symbolIsValue(symbol) && !isConstEnumSymbol(symbol) ? symbolToString(symbol): undefined; } function isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean { diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 037ef72f486..5eaeb3ae78d 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -148,6 +148,7 @@ module ts { A_rest_element_cannot_have_an_initializer: { code: 1186, category: DiagnosticCategory.Error, key: "A rest element cannot have an initializer." }, A_parameter_property_may_not_be_a_binding_pattern: { code: 1187, category: DiagnosticCategory.Error, key: "A parameter property may not be a binding pattern." }, An_import_declaration_cannot_have_modifiers: { code: 1188, category: DiagnosticCategory.Error, key: "An import declaration cannot have modifiers." }, + External_module_0_has_no_default_export_or_export_assignment: { code: 1189, category: DiagnosticCategory.Error, key: "External module '{0}' has no default export or export assignment." }, 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 af509a7d0da..d58cc0c552d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -583,6 +583,10 @@ "category": "Error", "code": 1188 }, + "External module '{0}' has no default export or export assignment.": { + "category": "Error", + "code": 1189 + }, "Duplicate identifier '{0}'.": { "category": "Error", diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 404a3a89504..d50b4bcf335 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1280,6 +1280,7 @@ module ts { declaredType?: Type; // Type of class, interface, enum, or type parameter mapper?: TypeMapper; // Type mapper for instantiation alias referenced?: boolean; // True if alias symbol has been referenced as a value + exportAssignChecked?: boolean; // True if export assignment was checked exportAssignSymbol?: Symbol; // Symbol exported from external module unionType?: UnionType; // Containing union type for union property }