diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e22bb18085c..228ee1d7468 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -486,9 +486,19 @@ namespace ts { if (location.kind === SyntaxKind.SourceFile || (location.kind === SyntaxKind.ModuleDeclaration && (location).name.kind === SyntaxKind.StringLiteral)) { - // It's an external module. Because of module/namespace merging, a module's exports are in scope, - // yet we never want to treat an export specifier as putting a member in scope. Therefore, - // if the name we find is purely an export specifier, it is not actually considered in scope. + // It's an external module. First see if the module has an export default and if the local + // name of that export default matches. + if (result = moduleExports["default"]) { + const localSymbol = getLocalSymbolForExportDefault(result); + if (localSymbol && (result.flags & meaning) && localSymbol.name === name) { + break loop; + } + result = undefined; + } + + // Because of module/namespace merging, a module's exports are in scope, + // yet we never want to treat an export specifier as putting a member in scope. + // Therefore, if the name we find is purely an export specifier, it is not actually considered in scope. // Two things to note about this: // 1. We have to check this without calling getSymbol. The problem with calling getSymbol // on an export specifier is that it might find the export specifier itself, and try to @@ -502,13 +512,6 @@ namespace ts { getDeclarationOfKind(moduleExports[name], SyntaxKind.ExportSpecifier)) { break; } - - result = moduleExports["default"]; - const localSymbol = getLocalSymbolForExportDefault(result); - if (result && localSymbol && (result.flags & meaning) && localSymbol.name === name) { - break loop; - } - result = undefined; } if (result = getSymbol(moduleExports, name, meaning & SymbolFlags.ModuleMember)) { @@ -4201,12 +4204,12 @@ namespace ts { // We only support expressions that are simple qualified names. For other expressions this produces undefined. const typeNameOrExpression = node.kind === SyntaxKind.TypeReference ? (node).typeName : isSupportedExpressionWithTypeArguments(node) ? (node).expression : - undefined; + undefined; const symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol; const type = symbol === unknownSymbol ? unknownType : symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? getTypeFromClassOrInterfaceReference(node, symbol) : - symbol.flags & SymbolFlags.TypeAlias ? getTypeFromTypeAliasReference(node, symbol) : - getTypeFromNonGenericTypeReference(node, symbol); + symbol.flags & SymbolFlags.TypeAlias ? getTypeFromTypeAliasReference(node, symbol) : + getTypeFromNonGenericTypeReference(node, symbol); // Cache both the resolved symbol and the resolved type. The resolved symbol is needed in when we check the // type reference in checkTypeReferenceOrExpressionWithTypeArguments. links.resolvedSymbol = symbol; @@ -11446,7 +11449,7 @@ namespace ts { // Abstract methods can't have an implementation -- in particular, they don't need one. if (!isExportSymbolInsideModule && lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body && - !(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract) ) { + !(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract)) { reportImplementationExpectedError(lastSeenNonAmbientDeclaration); } @@ -14380,8 +14383,8 @@ namespace ts { if (className) { copySymbol(location.symbol, meaning); } - // fall through; this fall-through is necessary because we would like to handle - // type parameter inside class expression similar to how we handle it in classDeclaration and interface Declaration + // fall through; this fall-through is necessary because we would like to handle + // type parameter inside class expression similar to how we handle it in classDeclaration and interface Declaration case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: // If we didn't come from static member of class or interface, @@ -14537,8 +14540,8 @@ namespace ts { return resolveEntityName(entityName, meaning); } else if ((entityName.parent.kind === SyntaxKind.JsxOpeningElement) || - (entityName.parent.kind === SyntaxKind.JsxSelfClosingElement) || - (entityName.parent.kind === SyntaxKind.JsxClosingElement)) { + (entityName.parent.kind === SyntaxKind.JsxSelfClosingElement) || + (entityName.parent.kind === SyntaxKind.JsxClosingElement)) { return getJsxElementTagSymbol(entityName.parent); } else if (isExpression(entityName)) { @@ -14605,8 +14608,8 @@ namespace ts { : getSymbolOfPartOfRightHandSideOfImportEquals(node); } else if (node.parent.kind === SyntaxKind.BindingElement && - node.parent.parent.kind === SyntaxKind.ObjectBindingPattern && - node === (node.parent).propertyName) { + node.parent.parent.kind === SyntaxKind.ObjectBindingPattern && + node === (node.parent).propertyName) { const typeOfPattern = getTypeOfNode(node.parent.parent); const propertyDeclaration = typeOfPattern && getPropertyOfType(typeOfPattern, (node).text); @@ -14643,7 +14646,7 @@ namespace ts { (node.parent).moduleSpecifier === node)) { return resolveExternalModuleName(node, node); } - // Fall through + // Fall through case SyntaxKind.NumericLiteral: // index access @@ -14839,7 +14842,7 @@ namespace ts { if (links.isNestedRedeclaration === undefined) { const container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); links.isNestedRedeclaration = isStatementWithLocals(container) && - !!resolveName(container.parent, symbol.name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); + !!resolveName(container.parent, symbol.name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); } return links.isNestedRedeclaration; } diff --git a/tests/baselines/reference/reExportDefaultExport.js b/tests/baselines/reference/reExportDefaultExport.js new file mode 100644 index 00000000000..dbe3dfdbbae --- /dev/null +++ b/tests/baselines/reference/reExportDefaultExport.js @@ -0,0 +1,27 @@ +//// [tests/cases/conformance/es6/modules/reExportDefaultExport.ts] //// + +//// [m1.ts] + +export default function f() { +} +export {f}; + + +//// [m2.ts] +import foo from "./m1"; +import {f} from "./m1"; + +f(); +foo(); + +//// [m1.js] +function f() { +} +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = f; +exports.f = f; +//// [m2.js] +var m1_1 = require("./m1"); +var m1_2 = require("./m1"); +m1_2.f(); +m1_1.default(); diff --git a/tests/baselines/reference/reExportDefaultExport.symbols b/tests/baselines/reference/reExportDefaultExport.symbols new file mode 100644 index 00000000000..cd0d6e493c9 --- /dev/null +++ b/tests/baselines/reference/reExportDefaultExport.symbols @@ -0,0 +1,22 @@ +=== tests/cases/conformance/es6/modules/m1.ts === + +export default function f() { +>f : Symbol(f, Decl(m1.ts, 0, 0)) +} +export {f}; +>f : Symbol(f, Decl(m1.ts, 3, 8)) + + +=== tests/cases/conformance/es6/modules/m2.ts === +import foo from "./m1"; +>foo : Symbol(foo, Decl(m2.ts, 0, 6)) + +import {f} from "./m1"; +>f : Symbol(f, Decl(m2.ts, 1, 8)) + +f(); +>f : Symbol(f, Decl(m2.ts, 1, 8)) + +foo(); +>foo : Symbol(foo, Decl(m2.ts, 0, 6)) + diff --git a/tests/baselines/reference/reExportDefaultExport.types b/tests/baselines/reference/reExportDefaultExport.types new file mode 100644 index 00000000000..f775571ac2c --- /dev/null +++ b/tests/baselines/reference/reExportDefaultExport.types @@ -0,0 +1,24 @@ +=== tests/cases/conformance/es6/modules/m1.ts === + +export default function f() { +>f : () => void +} +export {f}; +>f : () => void + + +=== tests/cases/conformance/es6/modules/m2.ts === +import foo from "./m1"; +>foo : () => void + +import {f} from "./m1"; +>f : () => void + +f(); +>f() : void +>f : () => void + +foo(); +>foo() : void +>foo : () => void + diff --git a/tests/cases/conformance/es6/modules/reExportDefaultExport.ts b/tests/cases/conformance/es6/modules/reExportDefaultExport.ts new file mode 100644 index 00000000000..730435fd4ee --- /dev/null +++ b/tests/cases/conformance/es6/modules/reExportDefaultExport.ts @@ -0,0 +1,15 @@ +// @module: commonjs +// @target: ES5 + +// @filename: m1.ts +export default function f() { +} +export {f}; + + +// @filename: m2.ts +import foo from "./m1"; +import {f} from "./m1"; + +f(); +foo(); \ No newline at end of file