From 6d0db0f401f731de6f0259059cdcbcb2b3c65aaa Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 6 Feb 2015 06:17:06 -0800 Subject: [PATCH] Resolve ES6 imports in type checker --- src/compiler/checker.ts | 125 ++++++++++++++++++++++++++++------------ 1 file changed, 89 insertions(+), 36 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4392c1c59b4..7f1450efac9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -439,22 +439,65 @@ module ts { return result; } + function getDeclarationOfImportSymbol(symbol: Symbol): Declaration { + return forEach(symbol.declarations, d => + d.kind === SyntaxKind.ImportEqualsDeclaration || + d.kind === SyntaxKind.ImportClause || + d.kind === SyntaxKind.NamespaceImport || + d.kind === SyntaxKind.ImportSpecifier ? d : undefined); + } + + function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol { + return node.moduleReference.kind === SyntaxKind.ExternalModuleReference ? + resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node)) : + 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); + } + + function getTargetOfNamespaceImport(node: NamespaceImport): Symbol { + // TODO: Verify that returned symbol does not originate in "export default" statement + return resolveExternalModuleName(node, (node.parent.parent).moduleSpecifier); + } + + function getTargetOfImportSpecifier(node: ImportSpecifier): Symbol { + var moduleSymbol = resolveExternalModuleName(node, (node.parent.parent.parent).moduleSpecifier); + if (moduleSymbol) { + var name = node.propertyName || node.name; + if (name.text) { + var symbol = getSymbol(moduleSymbol.exports, name.text, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace); + if (!symbol) { + error(name, Diagnostics.Module_0_has_no_exported_member_1, getFullyQualifiedName(moduleSymbol), declarationNameToString(name)); + return; + } + return symbol.flags & (SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace) ? symbol : resolveImport(symbol); + } + } + } + + function getTargetOfImportDeclaration(node: Declaration): Symbol { + switch (node.kind) { + case SyntaxKind.ImportEqualsDeclaration: + return getTargetOfImportEqualsDeclaration(node); + case SyntaxKind.ImportClause: + return getTargetOfImportClause(node); + case SyntaxKind.NamespaceImport: + return getTargetOfNamespaceImport(node); + case SyntaxKind.ImportSpecifier: + return getTargetOfImportSpecifier(node); + } + } + function resolveImport(symbol: Symbol): Symbol { Debug.assert((symbol.flags & SymbolFlags.Import) !== 0, "Should only get Imports here."); var links = getSymbolLinks(symbol); if (!links.target) { links.target = resolvingSymbol; - var node = getDeclarationOfKind(symbol, SyntaxKind.ImportEqualsDeclaration); - // Grammar checking - if (node.moduleReference.kind === SyntaxKind.ExternalModuleReference) { - if ((node.moduleReference).expression.kind !== SyntaxKind.StringLiteral) { - grammarErrorOnNode((node.moduleReference).expression, Diagnostics.String_literal_expected); - } - } - - var target = node.moduleReference.kind === SyntaxKind.ExternalModuleReference - ? resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node)) - : getSymbolOfPartOfRightHandSideOfImportEquals(node.moduleReference, node); + var node = getDeclarationOfImportSymbol(symbol); + var target = getTargetOfImportDeclaration(node); if (links.target === resolvingSymbol) { links.target = target || unknownSymbol; } @@ -4837,31 +4880,36 @@ module ts { var symbol = getResolvedSymbol(node); if (symbol.flags & SymbolFlags.Import) { - var symbolLinks = getSymbolLinks(symbol); - if (!symbolLinks.referenced) { - var importOrExportAssignment = getLeftSideOfImportEqualsOrExportAssignment(node); - // decision about whether import is referenced can be made now if - // - import that are used anywhere except right side of import declarations - // - imports that are used on the right side of exported import declarations - // for other cases defer decision until the check of left side - if (!importOrExportAssignment || - (importOrExportAssignment.flags & NodeFlags.Export) || - (importOrExportAssignment.kind === SyntaxKind.ExportAssignment)) { - // Mark the import as referenced so that we emit it in the final .js file. - // exception: identifiers that appear in type queries, const enums, modules that contain only const enums - symbolLinks.referenced = !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveImport(symbol)); - } - else { - var nodeLinks = getNodeLinks(importOrExportAssignment); - Debug.assert(!nodeLinks.importOnRightSide); - nodeLinks.importOnRightSide = symbol; - } - } + var symbolLinks = getSymbolLinks(symbol); + symbolLinks.referenced = !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveImport(symbol)); + + // TODO(andersh): Figure out what this does + //var symbolLinks = getSymbolLinks(symbol); + //if (!symbolLinks.referenced) { + // var importOrExportAssignment = getLeftSideOfImportEqualsOrExportAssignment(node); + + // // decision about whether import is referenced can be made now if + // // - import that are used anywhere except right side of import declarations + // // - imports that are used on the right side of exported import declarations + // // for other cases defer decision until the check of left side + // if (!importOrExportAssignment || + // (importOrExportAssignment.flags & NodeFlags.Export) || + // (importOrExportAssignment.kind === SyntaxKind.ExportAssignment)) { + // // Mark the import as referenced so that we emit it in the final .js file. + // // exception: identifiers that appear in type queries, const enums, modules that contain only const enums + // symbolLinks.referenced = !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveImport(symbol)); + // } + // else { + // var nodeLinks = getNodeLinks(importOrExportAssignment); + // Debug.assert(!nodeLinks.importOnRightSide); + // nodeLinks.importOnRightSide = symbol; + // } + //} - if (symbolLinks.referenced) { - markLinkedImportsAsReferenced(getDeclarationOfKind(symbol, SyntaxKind.ImportEqualsDeclaration)); - } + //if (symbolLinks.referenced) { + // markLinkedImportsAsReferenced(getDeclarationOfKind(symbol, SyntaxKind.ImportEqualsDeclaration)); + //} } checkCollisionWithCapturedSuperVariable(node, node); @@ -9228,6 +9276,10 @@ 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); @@ -9237,8 +9289,8 @@ module ts { // 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 (getExternalModuleImportEqualsDeclarationExpression(node).kind === SyntaxKind.StringLiteral) { - if (isExternalModuleNameRelative((getExternalModuleImportEqualsDeclarationExpression(node)).text)) { + 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; } @@ -11037,6 +11089,7 @@ module ts { // export_opt AmbientDeclaration // if (node.kind === SyntaxKind.InterfaceDeclaration || + node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration || node.kind === SyntaxKind.ExportAssignment || (node.flags & NodeFlags.Ambient)) {