@@ -51,6 +51,7 @@ namespace ts {
5151 const emitResolver = createResolver();
5252
5353 const undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined");
54+ undefinedSymbol.declarations = [];
5455 const argumentsSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "arguments");
5556
5657 const checker: TypeChecker = {
@@ -234,6 +235,10 @@ namespace ts {
234235 ResolvedReturnType
235236 }
236237
238+ const builtinGlobals: SymbolTable = {
239+ [undefinedSymbol.name]: undefinedSymbol
240+ };
241+
237242 initializeTypeChecker();
238243
239244 return checker;
@@ -360,6 +365,24 @@ namespace ts {
360365 }
361366 }
362367
368+ function addToSymbolTable(target: SymbolTable, source: SymbolTable, message: DiagnosticMessage) {
369+ for (const id in source) {
370+ if (hasProperty(source, id)) {
371+ if (hasProperty(target, id)) {
372+ // Error on redeclarations
373+ forEach(target[id].declarations, addDeclarationDiagnostic(id, message));
374+ }
375+ else {
376+ target[id] = source[id];
377+ }
378+ }
379+ }
380+
381+ function addDeclarationDiagnostic(id: string, message: DiagnosticMessage) {
382+ return (declaration: Declaration) => diagnostics.add(createDiagnosticForNode(declaration, message, id));
383+ }
384+ }
385+
363386 function getSymbolLinks(symbol: Symbol): SymbolLinks {
364387 if (symbol.flags & SymbolFlags.Transient) return <TransientSymbol>symbol;
365388 const id = getSymbolId(symbol);
@@ -1103,39 +1126,81 @@ namespace ts {
11031126 return links.resolvedExports || (links.resolvedExports = getExportsForModule(moduleSymbol));
11041127 }
11051128
1106- function extendExportSymbols(target: SymbolTable, source: SymbolTable) {
1129+ interface ExportCollisionTracker {
1130+ specifierText: string;
1131+ exportsWithDuplicate: ExportDeclaration[];
1132+ }
1133+
1134+ /**
1135+ * Extends one symbol table with another while collecting information on name collisions for error message generation into the `lookupTable` argument
1136+ * Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables
1137+ */
1138+ function extendExportSymbols(target: SymbolTable, source: SymbolTable, lookupTable?: Map<ExportCollisionTracker>, exportNode?: ExportDeclaration) {
11071139 for (const id in source) {
11081140 if (id !== "default" && !hasProperty(target, id)) {
11091141 target[id] = source[id];
1142+ if (lookupTable && exportNode) {
1143+ lookupTable[id] = {
1144+ specifierText: getTextOfNode(exportNode.moduleSpecifier)
1145+ } as ExportCollisionTracker;
1146+ }
1147+ }
1148+ else if (lookupTable && exportNode && id !== "default" && hasProperty(target, id) && resolveSymbol(target[id]) !== resolveSymbol(source[id])) {
1149+ if (!lookupTable[id].exportsWithDuplicate) {
1150+ lookupTable[id].exportsWithDuplicate = [exportNode];
1151+ }
1152+ else {
1153+ lookupTable[id].exportsWithDuplicate.push(exportNode);
1154+ }
11101155 }
11111156 }
11121157 }
11131158
11141159 function getExportsForModule(moduleSymbol: Symbol): SymbolTable {
1115- let result: SymbolTable;
11161160 const visitedSymbols: Symbol[] = [];
1117- visit(moduleSymbol);
1118- return result || moduleSymbol.exports;
1161+ return visit(moduleSymbol) || moduleSymbol.exports;
11191162
11201163 // The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example,
11211164 // module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error.
1122- function visit(symbol: Symbol) {
1123- if (symbol && symbol.flags & SymbolFlags.HasExports && !contains(visitedSymbols, symbol)) {
1124- visitedSymbols.push(symbol);
1125- if (symbol !== moduleSymbol) {
1126- if (!result) {
1127- result = cloneSymbolTable(moduleSymbol.exports);
1165+ function visit(symbol: Symbol): SymbolTable {
1166+ if (!(symbol && symbol.flags & SymbolFlags.HasExports && !contains(visitedSymbols, symbol))) {
1167+ return;
1168+ }
1169+ visitedSymbols.push(symbol);
1170+ const symbols = cloneSymbolTable(symbol.exports);
1171+ // All export * declarations are collected in an __export symbol by the binder
1172+ const exportStars = symbol.exports["__export"];
1173+ if (exportStars) {
1174+ const nestedSymbols: SymbolTable = {};
1175+ const lookupTable: Map<ExportCollisionTracker> = {};
1176+ for (const node of exportStars.declarations) {
1177+ const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier);
1178+ const exportedSymbols = visit(resolvedModule);
1179+ extendExportSymbols(
1180+ nestedSymbols,
1181+ exportedSymbols,
1182+ lookupTable,
1183+ node as ExportDeclaration
1184+ );
1185+ }
1186+ for (const id in lookupTable) {
1187+ const { exportsWithDuplicate } = lookupTable[id];
1188+ // It's not an error if the file with multiple `export *`s with duplicate names exports a member with that name itself
1189+ if (id === "export=" || !(exportsWithDuplicate && exportsWithDuplicate.length) || hasProperty(symbols, id)) {
1190+ continue;
11281191 }
1129- extendExportSymbols(result, symbol.exports);
1130- }
1131- // All export * declarations are collected in an __export symbol by the binder
1132- const exportStars = symbol.exports["__export"];
1133- if (exportStars) {
1134- for (const node of exportStars.declarations) {
1135- visit(resolveExternalModuleName(node, (<ExportDeclaration>node).moduleSpecifier ));
1192+ for (const node of exportsWithDuplicate) {
1193+ diagnostics.add(createDiagnosticForNode(
1194+ node,
1195+ Diagnostics.Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity,
1196+ lookupTable[id].specifierText,
1197+ id
1198+ ));
11361199 }
11371200 }
1201+ extendExportSymbols(symbols, nestedSymbols);
11381202 }
1203+ return symbols;
11391204 }
11401205 }
11411206
@@ -2948,10 +3013,6 @@ namespace ts {
29483013 return type.resolvedBaseConstructorType;
29493014 }
29503015
2951- function hasClassBaseType(type: InterfaceType): boolean {
2952- return !!forEach(getBaseTypes(type), t => !!(t.symbol.flags & SymbolFlags.Class));
2953- }
2954-
29553016 function getBaseTypes(type: InterfaceType): ObjectType[] {
29563017 const isClass = type.symbol.flags & SymbolFlags.Class;
29573018 const isInterface = type.symbol.flags & SymbolFlags.Interface;
@@ -3385,11 +3446,11 @@ namespace ts {
33853446 }
33863447
33873448 function getDefaultConstructSignatures(classType: InterfaceType): Signature[] {
3388- if (!hasClassBaseType(classType)) {
3389- return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)];
3390- }
33913449 const baseConstructorType = getBaseConstructorTypeOfClass(classType);
33923450 const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct);
3451+ if (baseSignatures.length === 0) {
3452+ return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)];
3453+ }
33933454 const baseTypeNode = getBaseTypeNodeOfClass(classType);
33943455 const typeArguments = map(baseTypeNode.typeArguments, getTypeFromTypeNode);
33953456 const typeArgCount = typeArguments ? typeArguments.length : 0;
@@ -3607,16 +3668,16 @@ namespace ts {
36073668 return <ResolvedType>type;
36083669 }
36093670
3610- // Return properties of an object type or an empty array for other types
3671+ /** Return properties of an object type or an empty array for other types */
36113672 function getPropertiesOfObjectType(type: Type): Symbol[] {
36123673 if (type.flags & TypeFlags.ObjectType) {
36133674 return resolveStructuredTypeMembers(<ObjectType>type).properties;
36143675 }
36153676 return emptyArray;
36163677 }
36173678
3618- // If the given type is an object type and that type has a property by the given name,
3619- // return the symbol for that property.Otherwise return undefined.
3679+ /** If the given type is an object type and that type has a property by the given name,
3680+ * return the symbol for that property. Otherwise return undefined. */
36203681 function getPropertyOfObjectType(type: Type, name: string): Symbol {
36213682 if (type.flags & TypeFlags.ObjectType) {
36223683 const resolved = resolveStructuredTypeMembers(<ObjectType>type);
@@ -14132,8 +14193,29 @@ namespace ts {
1413214193 const declaration = getDeclarationOfAliasSymbol(exportEqualsSymbol) || exportEqualsSymbol.valueDeclaration;
1413314194 error(declaration, Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements);
1413414195 }
14196+ // Checks for export * conflicts
14197+ const exports = getExportsOfModule(moduleSymbol);
14198+ for (const id in exports) {
14199+ if (id === "__export") {
14200+ continue;
14201+ }
14202+ const { declarations, flags } = exports[id];
14203+ // ECMA262: 15.2.1.1 It is a Syntax Error if the ExportedNames of ModuleItemList contains any duplicate entries. (TS Exceptions: namespaces, function overloads, enums, and interfaces)
14204+ if (!(flags & (SymbolFlags.Namespace | SymbolFlags.Interface | SymbolFlags.Enum)) && declarations.length > 1) {
14205+ const exportedDeclarations: Declaration[] = filter(declarations, isNotOverload);
14206+ if (exportedDeclarations.length > 1) {
14207+ for (const declaration of exportedDeclarations) {
14208+ diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Cannot_redeclare_exported_variable_0, id));
14209+ }
14210+ }
14211+ }
14212+ }
1413514213 links.exportsChecked = true;
1413614214 }
14215+
14216+ function isNotOverload(declaration: Declaration): boolean {
14217+ return declaration.kind !== SyntaxKind.FunctionDeclaration || !!(declaration as FunctionDeclaration).body;
14218+ }
1413714219 }
1413814220
1413914221 function checkTypePredicate(node: TypePredicateNode) {
@@ -15268,10 +15350,12 @@ namespace ts {
1526815350 }
1526915351 });
1527015352
15353+ // Setup global builtins
15354+ addToSymbolTable(globals, builtinGlobals, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0);
15355+
1527115356 getSymbolLinks(undefinedSymbol).type = undefinedType;
1527215357 getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments");
1527315358 getSymbolLinks(unknownSymbol).type = unknownType;
15274- globals[undefinedSymbol.name] = undefinedSymbol;
1527515359
1527615360 // Initialize special types
1527715361 globalArrayType = <GenericType>getGlobalType("Array", /*arity*/ 1);
0 commit comments