diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 296d18e891..5a01a421ce 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9336,18 +9336,78 @@ module ts { return node; } - function checkImportEqualsDeclaration(node: ImportEqualsDeclaration) { - // Grammar checking - checkGrammarModifiers(node); + function checkExternalImportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration): boolean { + var moduleName = getImportedModuleName(node); + if (getFullWidth(moduleName) !== 0 && moduleName.kind !== SyntaxKind.StringLiteral) { + error(moduleName, Diagnostics.String_literal_expected); + return false; + } + var inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && (node.parent.parent).name.kind === SyntaxKind.StringLiteral; + if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule) { + error(moduleName, Diagnostics.Import_declarations_in_an_internal_module_cannot_reference_an_external_module); + return false; + } + if (inAmbientExternalModule && isExternalModuleNameRelative((moduleName).text)) { + // TypeScript 1.0 spec (April 2013): 12.1.6 + // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference + // other external modules only through top - level external module names. + // Relative external module names are not permitted. + error(node, Diagnostics.Import_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name); + return false; + } + return true; + } + function checkImportSymbol(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportSpecifier) { + var symbol = getSymbolOfNode(node); + var target = resolveImport(symbol); + if (target !== unknownSymbol) { + var excludedMeanings = + (symbol.flags & SymbolFlags.Value ? SymbolFlags.Value : 0) | + (symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : 0) | + (symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : 0); + if (target.flags & excludedMeanings) { + error(node, Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0, symbolToString(symbol)); + } + } + } + + function checkImportBinding(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportSpecifier) { checkCollisionWithCapturedThisVariable(node, node.name); checkCollisionWithRequireExportsInGeneratedCode(node, node.name); - var symbol = getSymbolOfNode(node); - var target: Symbol; - + checkImportSymbol(node); + } + + function checkImportDeclaration(node: ImportDeclaration) { + if (!checkGrammarModifiers(node) && (node.flags & NodeFlags.Modifier)) { + grammarErrorOnFirstToken(node, Diagnostics.An_import_declaration_cannot_have_modifiers); + } + if (checkExternalImportDeclaration(node)) { + var importClause = node.importClause; + if (importClause) { + if (importClause.name) { + // TODO: Check that import references an export default instance + checkImportBinding(importClause); + } + if (importClause.namedBindings) { + // TODO: Check that import references an export namespace + if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { + checkImportBinding(importClause.namedBindings); + } + else { + forEach((importClause.namedBindings).elements, checkImportBinding); + } + } + } + } + } + + function checkImportEqualsDeclaration(node: ImportEqualsDeclaration) { + checkGrammarModifiers(node); if (isInternalModuleImportEqualsDeclaration(node)) { - target = resolveImport(symbol); - // Import declaration for an internal module + checkImportBinding(node); + var symbol = getSymbolOfNode(node); + var target = resolveImport(symbol); if (target !== unknownSymbol) { if (target.flags & SymbolFlags.Value) { // Target is a value symbol, check that it is not hidden by a local declaration with the same name and @@ -9366,44 +9426,8 @@ module ts { } } else { - var moduleNameExpr = getExternalModuleImportEqualsDeclarationExpression(node); - if (moduleNameExpr.kind !== SyntaxKind.StringLiteral) { - grammarErrorOnNode(moduleNameExpr, Diagnostics.String_literal_expected); - } - // Import declaration for an external module - if (node.parent.kind === SyntaxKind.SourceFile) { - target = resolveImport(symbol); - } - else if (node.parent.kind === SyntaxKind.ModuleBlock && (node.parent.parent).name.kind === SyntaxKind.StringLiteral) { - // TypeScript 1.0 spec (April 2013): 12.1.6 - // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference - // other external modules only through top - level external module names. - // Relative external module names are not permitted. - if (moduleNameExpr.kind === SyntaxKind.StringLiteral) { - if (isExternalModuleNameRelative((moduleNameExpr).text)) { - error(node, Diagnostics.Import_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name); - target = unknownSymbol; - } - else { - target = resolveImport(symbol); - } - } - else { - target = unknownSymbol; - } - } - else { - // Parent is an internal module (syntax error is already reported) - target = unknownSymbol; - } - } - if (target !== unknownSymbol) { - var excludedMeanings = - (symbol.flags & SymbolFlags.Value ? SymbolFlags.Value : 0) | - (symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : 0) | - (symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : 0); - if (target.flags & excludedMeanings) { - error(node, Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0, symbolToString(symbol)); + if (checkExternalImportDeclaration(node)) { + checkImportBinding(node); } } } @@ -9509,6 +9533,8 @@ module ts { return checkEnumDeclaration(node); case SyntaxKind.ModuleDeclaration: return checkModuleDeclaration(node); + case SyntaxKind.ImportDeclaration: + return checkImportDeclaration(node); case SyntaxKind.ImportEqualsDeclaration: return checkImportEqualsDeclaration(node); case SyntaxKind.ExportAssignment: @@ -10347,6 +10373,7 @@ module ts { case SyntaxKind.VariableStatement: case SyntaxKind.FunctionDeclaration: case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.ImportDeclaration: case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.Parameter: break; diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 1188d34619..037ef72f48 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -147,6 +147,7 @@ module ts { Merge_conflict_marker_encountered: { code: 1185, category: DiagnosticCategory.Error, key: "Merge conflict marker encountered." }, 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." }, 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 b1a794716a..af509a7d0d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -579,6 +579,10 @@ "category": "Error", "code": 1187 }, + "An import declaration cannot have modifiers.": { + "category": "Error", + "code": 1188 + }, "Duplicate identifier '{0}'.": { "category": "Error", diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 65e749ead2..1ac305cf05 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -3898,7 +3898,7 @@ module ts { } function emitRequire(moduleName: Expression) { - if (moduleName) { + if (moduleName.kind === SyntaxKind.StringLiteral) { write("require("); emitStart(moduleName); emitLiteral(moduleName); @@ -4080,8 +4080,8 @@ module ts { forEach(externalImports, info => { write(", "); var moduleName = getImportedModuleName(info.importNode); - if (moduleName) { - emitLiteral(moduleName); + if (moduleName.kind === SyntaxKind.StringLiteral) { + emitLiteral(moduleName); } else { write("\"\""); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 24d2b41b8f..ade6141952 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -352,21 +352,22 @@ module ts { function processImportedModules(file: SourceFile, basePath: string) { forEach(file.statements, node => { if (node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) { - var nameLiteral = getImportedModuleName(node); - var moduleName = nameLiteral && nameLiteral.text; - if (moduleName) { - var searchPath = basePath; - while (true) { - var searchName = normalizePath(combinePaths(searchPath, moduleName)); - if (findModuleSourceFile(searchName + ".ts", nameLiteral) || findModuleSourceFile(searchName + ".d.ts", nameLiteral)) { - break; + var moduleNameExpr = getImportedModuleName(node); + if (moduleNameExpr && moduleNameExpr.kind === SyntaxKind.StringLiteral) { + var moduleNameText = (moduleNameExpr).text; + if (moduleNameText) { + var searchPath = basePath; + while (true) { + var searchName = normalizePath(combinePaths(searchPath, moduleNameText)); + if (findModuleSourceFile(searchName + ".ts", moduleNameExpr) || findModuleSourceFile(searchName + ".d.ts", moduleNameExpr)) { + break; + } + var parentPath = getDirectoryPath(searchPath); + if (parentPath === searchPath) { + break; + } + searchPath = parentPath; } - - var parentPath = getDirectoryPath(searchPath); - if (parentPath === searchPath) { - break; - } - searchPath = parentPath; } } } @@ -397,7 +398,7 @@ module ts { } }); - function findModuleSourceFile(fileName: string, nameLiteral: LiteralExpression) { + function findModuleSourceFile(fileName: string, nameLiteral: Expression) { return findSourceFile(fileName, /* isDefaultLib */ false, file, nameLiteral.pos, nameLiteral.end - nameLiteral.pos); } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 27e959ca0c..6ce615c486 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -597,18 +597,14 @@ module ts { return node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind !== SyntaxKind.ExternalModuleReference; } - function extractStringLiteral(node: Expression): StringLiteralExpression { - return node && node.kind === SyntaxKind.StringLiteral ? node : undefined; - } - - export function getImportedModuleName(node: Node): StringLiteralExpression { + export function getImportedModuleName(node: Node): Expression { if (node.kind === SyntaxKind.ImportDeclaration) { - return extractStringLiteral((node).moduleSpecifier); + return (node).moduleSpecifier; } if (node.kind === SyntaxKind.ImportEqualsDeclaration) { var reference = (node).moduleReference; if (reference.kind === SyntaxKind.ExternalModuleReference) { - return extractStringLiteral((reference).expression); + return (reference).expression; } } }