From aa1ad5233e84dfe23c0978ee4070c940e2bcee05 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 28 Apr 2015 16:18:33 -0700 Subject: [PATCH 1/6] generate local storage for all exported names to avoid overwriting them via star exports --- src/compiler/emitter.ts | 150 ++++++++++++++++-- tests/baselines/reference/systemModule10.js | 4 +- .../baselines/reference/systemModule10_ES5.js | 4 +- .../reference/systemModule11.errors.txt | 50 +++++- tests/baselines/reference/systemModule11.js | 116 ++++++++++++-- tests/baselines/reference/systemModule9.js | 17 +- tests/cases/compiler/systemModule11.ts | 33 +++- 7 files changed, 329 insertions(+), 45 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 48718146ac6..b32c5f9f210 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -3,12 +3,6 @@ /* @internal */ module ts { - // represents one LexicalEnvironment frame to store unique generated names - interface ScopeFrame { - names: Map; - previous: ScopeFrame; - } - export function isExternalModuleOrDeclarationFile(sourceFile: SourceFile) { return isExternalModule(sourceFile) || isDeclarationFile(sourceFile); } @@ -18,7 +12,6 @@ module ts { Auto = 0x00000000, // No preferred name CountMask = 0x0FFFFFFF, // Temp variable counter _i = 0x10000000, // Use/preference flag for '_i' - _n = 0x20000000, // Use/preference flag for '_n' } // targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature @@ -2683,15 +2676,17 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { if (!exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, name.text)) { for (let specifier of exportSpecifiers[name.text]) { writeLine(); - emitStart(specifier.name); if (compilerOptions.module === ModuleKind.System) { + emitStart(specifier.name); write(`${exportFunctionForFile}("`); emitNodeWithoutSourceMap(specifier.name); write(`", `); emitExpressionIdentifier(name); write(")") + emitEnd(specifier.name); } else { + emitStart(specifier.name); emitContainingModuleName(specifier); write("."); emitNodeWithoutSourceMap(specifier.name); @@ -4968,7 +4963,108 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { } } - function hoistTopLevelVariableAndFunctionDeclarations(node: SourceFile): void { + function emitLocalStorageForExportedNamesIfNecessary(exportedDeclarations: (Identifier | Declaration)[]): string { + // when resolving exports local exported entries/indirect exported entries in the module + // should always win over entries with similar names that were added via star exports + // to support this we store names of local/indirect exported entries in a set. + // this set is used to filter names brought by star expors. + + if (!hasExportStars) { + // local names set is needed only in presence of star exports + return undefined; + } + + // local names set should only be added if we have anything exported + if (!exportedDeclarations && isEmpty(exportSpecifiers)) { + // no exported declarations (export var ...) or export specifiers (export {x}) + // check if we have any non star export declarations. + let hasExportDeclarationWithExportClause = false; + for (let externalImport of externalImports) { + if (externalImport.kind === SyntaxKind.ExportDeclaration && (externalImport).exportClause) { + hasExportDeclarationWithExportClause = true; + break; + } + } + + if (!hasExportDeclarationWithExportClause) { + // nothing is exported + return undefined; + } + } + + const exportedNamesStorageRef = makeUniqueName("exportedNames"); + + writeLine(); + write(`var ${exportedNamesStorageRef} = { `); + increaseIndent(); + + let started = false; + if (exportedDeclarations) { + for (let i = 0; i < exportedDeclarations.length; ++i) { + // write name of exported declaration, i.e 'export var x...' + writeExportedName(exportedDeclarations[i]); + } + } + + if (exportSpecifiers) { + for (let n in exportSpecifiers) { + for (let specifier of exportSpecifiers[n]) { + // write name of export specified, i.e. 'export {x}' + writeExportedName(specifier.name); + } + } + } + + if (externalImports) { + for (let externalImport of externalImports) { + if (externalImport.kind !== SyntaxKind.ExportDeclaration) { + continue; + } + + let exportDecl = externalImport; + if (!exportDecl.exportClause) { + // export * from ... + continue; + } + + for (let element of exportDecl.exportClause.elements) { + // write name of indirectly exported entry, i.e. 'export {x} from ...' + writeExportedName(element.name || element.propertyName); + } + } + } + + decreaseIndent(); + writeLine(); + write("};"); + + return exportedNamesStorageRef; + + function writeExportedName(node: Identifier | Declaration): void { + if (started) { + write(","); + } + else { + started = true; + } + + writeLine(); + write("'"); + if (node.kind === SyntaxKind.Identifier) { + emitNodeWithoutSourceMap(node); + } + else if (node.flags & NodeFlags.Default) { + write("default"); + } + else { + emitDeclarationName(node); + } + + write("': true"); + } + } + + function processTopLevelVariableAndFunctionDeclarations(node: SourceFile): (Identifier | Declaration)[] { // per ES6 spec: // 15.2.1.16.4 ModuleDeclarationInstantiation() Concrete Method // - var declarations are initialized to undefined - 14.a.ii @@ -4980,6 +5076,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { // including variables declarations for module and class declarations let hoistedVars: (Identifier | ClassDeclaration | ModuleDeclaration)[]; let hoistedFunctionDeclarations: FunctionDeclaration[]; + let exportedDeclarations: (Identifier | Declaration)[]; visit(node); @@ -4997,6 +5094,14 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { else { emit(local); } + + let flags = getCombinedNodeFlags(local.kind === SyntaxKind.Identifier ? local.parent : local); + if (flags & NodeFlags.Export) { + if (!exportedDeclarations) { + exportedDeclarations = []; + } + exportedDeclarations.push(local); + } } write(";") } @@ -5005,9 +5110,18 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { for (let f of hoistedFunctionDeclarations) { writeLine(); emit(f); + + if (f.flags & NodeFlags.Export) { + if (!exportedDeclarations) { + exportedDeclarations = []; + } + exportedDeclarations.push(f); + } } } + return exportedDeclarations; + function visit(node: Node): void { if (node.kind === SyntaxKind.FunctionDeclaration) { if (!hoistedFunctionDeclarations) { @@ -5121,12 +5235,13 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { // } emitVariableDeclarationsForImports(); writeLine(); - hoistTopLevelVariableAndFunctionDeclarations(node); + var exportedDeclarations = processTopLevelVariableAndFunctionDeclarations(node); + let exportedLocalNames = emitLocalStorageForExportedNamesIfNecessary(exportedDeclarations) writeLine(); write("return {"); increaseIndent(); writeLine(); - emitSetters(); + emitSetters(exportedLocalNames); writeLine(); emitExecute(node, startIndex); emitTempDeclarations(/*newLine*/ true) @@ -5135,7 +5250,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { write("}"); // return } - function emitSetters() { + function emitSetters(exportedLocalNamesRef: string) { write("setters:["); for (let i = 0; i < externalImports.length; ++i) { if (i !== 0) { @@ -5163,7 +5278,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { increaseIndent(); writeLine(); // save import into the local - write(`${importVariableName} = ${parameterName}`); + write(`${importVariableName} = ${parameterName};`); writeLine(); let defaultName = @@ -5230,7 +5345,14 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { // emit as: // for (var n in _foo) exports(n, _foo[n]); // NOTE: it is safe to use name 'n' since parameter name always starts with '_' - write(`for (var n in ${parameterName}) ${exportFunctionForFile}(n, ${parameterName}[n]);`); + write(`for (var n in ${parameterName})`); + increaseIndent(); + writeLine(); + if (exportedLocalNamesRef) { + write(`if (!${exportedLocalNamesRef}.hasOwnProperty(n))`); + } + write(` ${exportFunctionForFile}(n, ${parameterName}[n]);`) + decreaseIndent(); } writeLine(); diff --git a/tests/baselines/reference/systemModule10.js b/tests/baselines/reference/systemModule10.js index 66e7e9755d1..c63b3589085 100644 --- a/tests/baselines/reference/systemModule10.js +++ b/tests/baselines/reference/systemModule10.js @@ -15,14 +15,14 @@ System.register(['file1', 'file2'], function(exports_1) { return { setters:[ function (_file1_1) { - file1_1 = _file1_1 + file1_1 = _file1_1; exports_1("n", file1_1["default"]); exports_1("n1", file1_1["default"]); exports_1("x", file1_1.x); exports_1("y", file1_1.x); }, function (_n2) { - n2 = _n2 + n2 = _n2; exports_1("n2", n2); exports_1("n3", n2); }], diff --git a/tests/baselines/reference/systemModule10_ES5.js b/tests/baselines/reference/systemModule10_ES5.js index 04c946d9abe..bdb920414de 100644 --- a/tests/baselines/reference/systemModule10_ES5.js +++ b/tests/baselines/reference/systemModule10_ES5.js @@ -15,14 +15,14 @@ System.register(['file1', 'file2'], function(exports_1) { return { setters:[ function (_file1_1) { - file1_1 = _file1_1 + file1_1 = _file1_1; exports_1("n", file1_1.default); exports_1("n1", file1_1.default); exports_1("x", file1_1.x); exports_1("y", file1_1.x); }, function (_n2) { - n2 = _n2 + n2 = _n2; exports_1("n2", n2); exports_1("n3", n2); }], diff --git a/tests/baselines/reference/systemModule11.errors.txt b/tests/baselines/reference/systemModule11.errors.txt index a2c30e5fa64..2ea3e97daf9 100644 --- a/tests/baselines/reference/systemModule11.errors.txt +++ b/tests/baselines/reference/systemModule11.errors.txt @@ -1,11 +1,49 @@ -tests/cases/compiler/systemModule11.ts(3,17): error TS2307: Cannot find external module 'bar'. +tests/cases/compiler/file1.ts(7,15): error TS2307: Cannot find external module 'bar'. +tests/cases/compiler/file2.ts(7,15): error TS2307: Cannot find external module 'bar'. +tests/cases/compiler/file3.ts(2,25): error TS2307: Cannot find external module 'a'. +tests/cases/compiler/file3.ts(3,15): error TS2307: Cannot find external module 'bar'. +tests/cases/compiler/file4.ts(8,27): error TS2307: Cannot find external module 'a'. -==== tests/cases/compiler/systemModule11.ts (1 errors) ==== +==== tests/cases/compiler/file1.ts (1 errors) ==== - import 'foo' - import {f} from 'bar'; - ~~~~~ + // set of tests cases that checks generation of local storage for exported names + + + export var x; + export function foo() {} + export * from 'bar'; + ~~~~~ !!! error TS2307: Cannot find external module 'bar'. - f(); \ No newline at end of file +==== tests/cases/compiler/file2.ts (1 errors) ==== + + var x; + var y; + export {x}; + export {y as y1} + + export * from 'bar'; + ~~~~~ +!!! error TS2307: Cannot find external module 'bar'. + +==== tests/cases/compiler/file3.ts (2 errors) ==== + + export {x, y as z} from 'a'; + ~~~ +!!! error TS2307: Cannot find external module 'a'. + export * from 'bar'; + ~~~~~ +!!! error TS2307: Cannot find external module 'bar'. + +==== tests/cases/compiler/file4.ts (1 errors) ==== + + export var x; + export function foo() {} + + var z, z1; + export {z, z1 as z2}; + + export {s, s1 as s2} from 'a' + ~~~ +!!! error TS2307: Cannot find external module 'a'. \ No newline at end of file diff --git a/tests/baselines/reference/systemModule11.js b/tests/baselines/reference/systemModule11.js index f04cabcf935..85e275ebbcf 100644 --- a/tests/baselines/reference/systemModule11.js +++ b/tests/baselines/reference/systemModule11.js @@ -1,21 +1,113 @@ -//// [systemModule11.ts] - -import 'foo' -import {f} from 'bar'; - -f(); +//// [tests/cases/compiler/systemModule11.ts] //// -//// [systemModule11.js] -System.register(['foo', 'bar'], function(exports_1) { - var bar_1; +//// [file1.ts] + +// set of tests cases that checks generation of local storage for exported names + + +export var x; +export function foo() {} +export * from 'bar'; + +//// [file2.ts] + +var x; +var y; +export {x}; +export {y as y1} + +export * from 'bar'; + +//// [file3.ts] + +export {x, y as z} from 'a'; +export * from 'bar'; + +//// [file4.ts] + +export var x; +export function foo() {} + +var z, z1; +export {z, z1 as z2}; + +export {s, s1 as s2} from 'a' + +//// [file1.js] +// set of tests cases that checks generation of local storage for exported names +System.register(['bar'], function(exports_1) { + var x; + function foo() { } + exports_1("foo", foo); + var exportedNames_1 = { + 'x': true, + 'foo': true + }; return { setters:[ - function (_) {}, function (_bar_1) { - bar_1 = _bar_1 + for (var n in _bar_1) + if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _bar_1[n]); }], execute: function() { - bar_1.f(); + exports_1("x", x); + } + } +}); +//// [file2.js] +System.register(['bar'], function(exports_1) { + var x, y; + var exportedNames_1 = { + 'x': true, + 'y1': true + }; + return { + setters:[ + function (_bar_1) { + for (var n in _bar_1) + if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _bar_1[n]); + }], + execute: function() { + exports_1("x", x); + exports_1("y1", y); + } + } +}); +//// [file3.js] +System.register(['a', 'bar'], function(exports_1) { + var exportedNames_1 = { + 'x': true, + 'z': true + }; + return { + setters:[ + function (_a_1) { + exports_1("x", _a_1["x"]); + exports_1("z", _a_1["y"]); + }, + function (_bar_1) { + for (var n in _bar_1) + if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _bar_1[n]); + }], + execute: function() { + } + } +}); +//// [file4.js] +System.register(['a'], function(exports_1) { + var x, z, z1; + function foo() { } + exports_1("foo", foo); + return { + setters:[ + function (_a_1) { + exports_1("s", _a_1["s"]); + exports_1("s2", _a_1["s1"]); + }], + execute: function() { + exports_1("x", x); + exports_1("z", z); + exports_1("z2", z1); } } }); diff --git a/tests/baselines/reference/systemModule9.js b/tests/baselines/reference/systemModule9.js index 831aa778f38..55f7707ecb1 100644 --- a/tests/baselines/reference/systemModule9.js +++ b/tests/baselines/reference/systemModule9.js @@ -25,26 +25,31 @@ export {y as z}; System.register(['file1', 'file2', 'file3', 'file4', 'file5', 'file6', 'file7'], function(exports_1) { var ns, file2_1, file3_1, file5_1, ns3; var x, y; + var exportedNames_1 = { + 'x': true, + 'z': true + }; return { setters:[ function (_ns) { - ns = _ns + ns = _ns; }, function (_file2_1) { - file2_1 = _file2_1 + file2_1 = _file2_1; }, function (_file3_1) { - file3_1 = _file3_1 + file3_1 = _file3_1; }, function (_) {}, function (_file5_1) { - file5_1 = _file5_1 + file5_1 = _file5_1; }, function (_ns3) { - ns3 = _ns3 + ns3 = _ns3; }, function (_file7_1) { - for (var n in _file7_1) exports_1(n, _file7_1[n]); + for (var n in _file7_1) + if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _file7_1[n]); }], execute: function() { ns.f(); diff --git a/tests/cases/compiler/systemModule11.ts b/tests/cases/compiler/systemModule11.ts index 023b4f5f56b..9e27cc919ab 100644 --- a/tests/cases/compiler/systemModule11.ts +++ b/tests/cases/compiler/systemModule11.ts @@ -1,7 +1,34 @@ // @module: system // @separateCompilation: true -import 'foo' -import {f} from 'bar'; +// set of tests cases that checks generation of local storage for exported names -f(); \ No newline at end of file +// @filename: file1.ts + +export var x; +export function foo() {} +export * from 'bar'; + +// @filename: file2.ts + +var x; +var y; +export {x}; +export {y as y1} + +export * from 'bar'; + +// @filename: file3.ts + +export {x, y as z} from 'a'; +export * from 'bar'; + +// @filename: file4.ts + +export var x; +export function foo() {} + +var z, z1; +export {z, z1 as z2}; + +export {s, s1 as s2} from 'a' \ No newline at end of file From 7037c6be11e9ccc657f9d7292f6c3d30874fc9b1 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 28 Apr 2015 16:37:08 -0700 Subject: [PATCH 2/6] removed redundant check --- src/compiler/emitter.ts | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 0a0950373ce..235e28b8203 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -5015,22 +5015,20 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { } } - if (externalImports) { - for (let externalImport of externalImports) { - if (externalImport.kind !== SyntaxKind.ExportDeclaration) { - continue; - } + for (let externalImport of externalImports) { + if (externalImport.kind !== SyntaxKind.ExportDeclaration) { + continue; + } - let exportDecl = externalImport; - if (!exportDecl.exportClause) { - // export * from ... - continue; - } + let exportDecl = externalImport; + if (!exportDecl.exportClause) { + // export * from ... + continue; + } - for (let element of exportDecl.exportClause.elements) { - // write name of indirectly exported entry, i.e. 'export {x} from ...' - writeExportedName(element.name || element.propertyName); - } + for (let element of exportDecl.exportClause.elements) { + // write name of indirectly exported entry, i.e. 'export {x} from ...' + writeExportedName(element.name || element.propertyName); } } From 3af5592243bbb33ca3f2895cbdae2711e7709e49 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 28 Apr 2015 18:51:29 -0700 Subject: [PATCH 3/6] allow module to reserve slots for names that they export --- src/compiler/emitter.ts | 51 ++++++++++++++------- tests/baselines/reference/systemModule11.js | 45 ++++++++++++------ tests/baselines/reference/systemModule9.js | 15 ++++-- 3 files changed, 75 insertions(+), 36 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 235e28b8203..aa65406b426 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -4992,10 +4992,18 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { } } + // storage has the following structure + // { + // : void 0, + // : 'm' + // } + // this allows to: + // - prevent star exports to overwrite locally exported names + // - bind star exported names to particular module so they won't be overwritten by other star exports const exportedNamesStorageRef = makeUniqueName("exportedNames"); writeLine(); - write(`var ${exportedNamesStorageRef} = { `); + write(`var ${exportedNamesStorageRef} = {`); increaseIndent(); let started = false; @@ -5036,7 +5044,26 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { writeLine(); write("};"); - return exportedNamesStorageRef; + writeLine(); + + const exportStarFunction = makeUniqueName("exportStar"); + + // define an export star helper function + write(`function ${exportStarFunction}(m, name) {`); + writeLine(); + write(` for(var n in m) {`); + writeLine(); + // if name is not yet taken by either local names or names in other modules - reserve it + write(` if (!${exportedNamesStorageRef}.hasOwnProperty(n)) ${exportedNamesStorageRef}[n] = name;`); + writeLine(); + // only export value if it was exported from the module with name 'name'; + write(` if (${exportedNamesStorageRef}[n] === name) ${exportFunctionForFile}(n, m[n]);`); + writeLine(); + write(" }"); + writeLine(); + write("}") + + return exportStarFunction; function writeExportedName(node: Identifier | Declaration): void { if (started) { @@ -5058,7 +5085,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { emitDeclarationName(node); } - write("': true"); + write("': void 0"); } } @@ -5234,12 +5261,12 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { emitVariableDeclarationsForImports(); writeLine(); var exportedDeclarations = processTopLevelVariableAndFunctionDeclarations(node); - let exportedLocalNames = emitLocalStorageForExportedNamesIfNecessary(exportedDeclarations) + let exportStarFunction = emitLocalStorageForExportedNamesIfNecessary(exportedDeclarations) writeLine(); write("return {"); increaseIndent(); writeLine(); - emitSetters(exportedLocalNames); + emitSetters(exportStarFunction); writeLine(); emitExecute(node, startIndex); emitTempDeclarations(/*newLine*/ true) @@ -5248,7 +5275,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { write("}"); // return } - function emitSetters(exportedLocalNamesRef: string) { + function emitSetters(exportStarFunction: string) { write("setters:["); for (let i = 0; i < externalImports.length; ++i) { if (i !== 0) { @@ -5341,16 +5368,8 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { writeLine(); // export * from 'foo' // emit as: - // for (var n in _foo) exports(n, _foo[n]); - // NOTE: it is safe to use name 'n' since parameter name always starts with '_' - write(`for (var n in ${parameterName})`); - increaseIndent(); - writeLine(); - if (exportedLocalNamesRef) { - write(`if (!${exportedLocalNamesRef}.hasOwnProperty(n))`); - } - write(` ${exportFunctionForFile}(n, ${parameterName}[n]);`) - decreaseIndent(); + // exportStar(_foo, 'foo'); + write(`${exportStarFunction}(${parameterName}, ${getExternalModuleNameText(importNode)});`); } writeLine(); diff --git a/tests/baselines/reference/systemModule11.js b/tests/baselines/reference/systemModule11.js index 85e275ebbcf..c42719ac031 100644 --- a/tests/baselines/reference/systemModule11.js +++ b/tests/baselines/reference/systemModule11.js @@ -39,15 +39,20 @@ System.register(['bar'], function(exports_1) { var x; function foo() { } exports_1("foo", foo); - var exportedNames_1 = { - 'x': true, - 'foo': true + var exportedNames_1 = { + 'x': void 0, + 'foo': void 0 }; + function exportStar_1(m, name) { + for(var n in m) { + if (!exportedNames_1.hasOwnProperty(n)) exportedNames_1[n] = name; + if (exportedNames_1[n] === name) exports_1(n, m[n]); + } + } return { setters:[ function (_bar_1) { - for (var n in _bar_1) - if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _bar_1[n]); + exportStar_1(_bar_1, 'bar'); }], execute: function() { exports_1("x", x); @@ -57,15 +62,20 @@ System.register(['bar'], function(exports_1) { //// [file2.js] System.register(['bar'], function(exports_1) { var x, y; - var exportedNames_1 = { - 'x': true, - 'y1': true + var exportedNames_1 = { + 'x': void 0, + 'y1': void 0 }; + function exportStar_1(m, name) { + for(var n in m) { + if (!exportedNames_1.hasOwnProperty(n)) exportedNames_1[n] = name; + if (exportedNames_1[n] === name) exports_1(n, m[n]); + } + } return { setters:[ function (_bar_1) { - for (var n in _bar_1) - if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _bar_1[n]); + exportStar_1(_bar_1, 'bar'); }], execute: function() { exports_1("x", x); @@ -75,10 +85,16 @@ System.register(['bar'], function(exports_1) { }); //// [file3.js] System.register(['a', 'bar'], function(exports_1) { - var exportedNames_1 = { - 'x': true, - 'z': true + var exportedNames_1 = { + 'x': void 0, + 'z': void 0 }; + function exportStar_1(m, name) { + for(var n in m) { + if (!exportedNames_1.hasOwnProperty(n)) exportedNames_1[n] = name; + if (exportedNames_1[n] === name) exports_1(n, m[n]); + } + } return { setters:[ function (_a_1) { @@ -86,8 +102,7 @@ System.register(['a', 'bar'], function(exports_1) { exports_1("z", _a_1["y"]); }, function (_bar_1) { - for (var n in _bar_1) - if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _bar_1[n]); + exportStar_1(_bar_1, 'bar'); }], execute: function() { } diff --git a/tests/baselines/reference/systemModule9.js b/tests/baselines/reference/systemModule9.js index 55f7707ecb1..27b274e8ab6 100644 --- a/tests/baselines/reference/systemModule9.js +++ b/tests/baselines/reference/systemModule9.js @@ -25,10 +25,16 @@ export {y as z}; System.register(['file1', 'file2', 'file3', 'file4', 'file5', 'file6', 'file7'], function(exports_1) { var ns, file2_1, file3_1, file5_1, ns3; var x, y; - var exportedNames_1 = { - 'x': true, - 'z': true + var exportedNames_1 = { + 'x': void 0, + 'z': void 0 }; + function exportStar_1(m, name) { + for(var n in m) { + if (!exportedNames_1.hasOwnProperty(n)) exportedNames_1[n] = name; + if (exportedNames_1[n] === name) exports_1(n, m[n]); + } + } return { setters:[ function (_ns) { @@ -48,8 +54,7 @@ System.register(['file1', 'file2', 'file3', 'file4', 'file5', 'file6', 'file7'], ns3 = _ns3; }, function (_file7_1) { - for (var n in _file7_1) - if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _file7_1[n]); + exportStar_1(_file7_1, 'file7'); }], execute: function() { ns.f(); From 5f18d9b912320bbddaffef8ab74207c094f5ec3d Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 28 Apr 2015 20:17:55 -0700 Subject: [PATCH 4/6] extract emitExportStar in separate function --- src/compiler/emitter.ts | 59 +++++++++---------- .../reference/systemModule11.errors.txt | 8 +++ tests/baselines/reference/systemModule11.js | 57 ++++++++++++------ tests/baselines/reference/systemModule9.js | 11 ++-- tests/cases/compiler/systemModule11.ts | 7 ++- 5 files changed, 84 insertions(+), 58 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index aa65406b426..672a6b32126 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -4968,7 +4968,6 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { // should always win over entries with similar names that were added via star exports // to support this we store names of local/indirect exported entries in a set. // this set is used to filter names brought by star expors. - if (!hasExportStars) { // local names set is needed only in presence of star exports return undefined; @@ -4987,19 +4986,11 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { } if (!hasExportDeclarationWithExportClause) { - // nothing is exported - return undefined; + // we still need to emit exportStar helper + return emitExportStarFunction(/*localNames*/ undefined); } } - // storage has the following structure - // { - // : void 0, - // : 'm' - // } - // this allows to: - // - prevent star exports to overwrite locally exported names - // - bind star exported names to particular module so they won't be overwritten by other star exports const exportedNamesStorageRef = makeUniqueName("exportedNames"); writeLine(); @@ -5044,27 +5035,31 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { writeLine(); write("};"); - writeLine(); - - const exportStarFunction = makeUniqueName("exportStar"); + return emitExportStarFunction(exportedNamesStorageRef); - // define an export star helper function - write(`function ${exportStarFunction}(m, name) {`); - writeLine(); - write(` for(var n in m) {`); - writeLine(); - // if name is not yet taken by either local names or names in other modules - reserve it - write(` if (!${exportedNamesStorageRef}.hasOwnProperty(n)) ${exportedNamesStorageRef}[n] = name;`); - writeLine(); - // only export value if it was exported from the module with name 'name'; - write(` if (${exportedNamesStorageRef}[n] === name) ${exportFunctionForFile}(n, m[n]);`); - writeLine(); - write(" }"); - writeLine(); - write("}") + function emitExportStarFunction(localNames: string): string { + const exportStarFunction = makeUniqueName("exportStar"); - return exportStarFunction; + writeLine(); + // define an export star helper function + write(`function ${exportStarFunction}(m) {`); + writeLine(); + write(` for(var n in m) {`); + writeLine(); + write(` `); + if (localNames) { + write(`if (!${localNames}.hasOwnProperty(n)) `); + } + write(`${exportFunctionForFile}(n, m[n]);`); + writeLine(); + write(" }"); + writeLine(); + write("}") + + return exportStarFunction; + } + function writeExportedName(node: Identifier | Declaration): void { if (started) { write(","); @@ -5085,7 +5080,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { emitDeclarationName(node); } - write("': void 0"); + write("': true"); } } @@ -5368,8 +5363,8 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { writeLine(); // export * from 'foo' // emit as: - // exportStar(_foo, 'foo'); - write(`${exportStarFunction}(${parameterName}, ${getExternalModuleNameText(importNode)});`); + // exportStar(_foo); + write(`${exportStarFunction}(${parameterName});`); } writeLine(); diff --git a/tests/baselines/reference/systemModule11.errors.txt b/tests/baselines/reference/systemModule11.errors.txt index 8f3ff1c87df..f45de9a7783 100644 --- a/tests/baselines/reference/systemModule11.errors.txt +++ b/tests/baselines/reference/systemModule11.errors.txt @@ -3,6 +3,7 @@ tests/cases/compiler/file2.ts(7,15): error TS2307: Cannot find module 'bar'. tests/cases/compiler/file3.ts(2,25): error TS2307: Cannot find module 'a'. tests/cases/compiler/file3.ts(3,15): error TS2307: Cannot find module 'bar'. tests/cases/compiler/file4.ts(8,27): error TS2307: Cannot find module 'a'. +tests/cases/compiler/file5.ts(3,15): error TS2307: Cannot find module 'a'. ==== tests/cases/compiler/file1.ts (1 errors) ==== @@ -46,4 +47,11 @@ tests/cases/compiler/file4.ts(8,27): error TS2307: Cannot find module 'a'. export {s, s1 as s2} from 'a' ~~~ +!!! error TS2307: Cannot find module 'a'. + +==== tests/cases/compiler/file5.ts (1 errors) ==== + + function foo() {} + export * from 'a'; + ~~~ !!! error TS2307: Cannot find module 'a'. \ No newline at end of file diff --git a/tests/baselines/reference/systemModule11.js b/tests/baselines/reference/systemModule11.js index c42719ac031..56c3125f553 100644 --- a/tests/baselines/reference/systemModule11.js +++ b/tests/baselines/reference/systemModule11.js @@ -31,7 +31,12 @@ export function foo() {} var z, z1; export {z, z1 as z2}; -export {s, s1 as s2} from 'a' +export {s, s1 as s2} from 'a' + +//// [file5.ts] + +function foo() {} +export * from 'a'; //// [file1.js] // set of tests cases that checks generation of local storage for exported names @@ -40,19 +45,18 @@ System.register(['bar'], function(exports_1) { function foo() { } exports_1("foo", foo); var exportedNames_1 = { - 'x': void 0, - 'foo': void 0 + 'x': true, + 'foo': true }; - function exportStar_1(m, name) { + function exportStar_1(m) { for(var n in m) { - if (!exportedNames_1.hasOwnProperty(n)) exportedNames_1[n] = name; - if (exportedNames_1[n] === name) exports_1(n, m[n]); + if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, m[n]); } } return { setters:[ function (_bar_1) { - exportStar_1(_bar_1, 'bar'); + exportStar_1(_bar_1); }], execute: function() { exports_1("x", x); @@ -63,19 +67,18 @@ System.register(['bar'], function(exports_1) { System.register(['bar'], function(exports_1) { var x, y; var exportedNames_1 = { - 'x': void 0, - 'y1': void 0 + 'x': true, + 'y1': true }; - function exportStar_1(m, name) { + function exportStar_1(m) { for(var n in m) { - if (!exportedNames_1.hasOwnProperty(n)) exportedNames_1[n] = name; - if (exportedNames_1[n] === name) exports_1(n, m[n]); + if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, m[n]); } } return { setters:[ function (_bar_1) { - exportStar_1(_bar_1, 'bar'); + exportStar_1(_bar_1); }], execute: function() { exports_1("x", x); @@ -86,13 +89,12 @@ System.register(['bar'], function(exports_1) { //// [file3.js] System.register(['a', 'bar'], function(exports_1) { var exportedNames_1 = { - 'x': void 0, - 'z': void 0 + 'x': true, + 'z': true }; - function exportStar_1(m, name) { + function exportStar_1(m) { for(var n in m) { - if (!exportedNames_1.hasOwnProperty(n)) exportedNames_1[n] = name; - if (exportedNames_1[n] === name) exports_1(n, m[n]); + if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, m[n]); } } return { @@ -102,7 +104,7 @@ System.register(['a', 'bar'], function(exports_1) { exports_1("z", _a_1["y"]); }, function (_bar_1) { - exportStar_1(_bar_1, 'bar'); + exportStar_1(_bar_1); }], execute: function() { } @@ -126,3 +128,20 @@ System.register(['a'], function(exports_1) { } } }); +//// [file5.js] +System.register(['a'], function(exports_1) { + function foo() { } + function exportStar_1(m) { + for(var n in m) { + exports_1(n, m[n]); + } + } + return { + setters:[ + function (_a_1) { + exportStar_1(_a_1); + }], + execute: function() { + } + } +}); diff --git a/tests/baselines/reference/systemModule9.js b/tests/baselines/reference/systemModule9.js index 27b274e8ab6..2cc7bc68d73 100644 --- a/tests/baselines/reference/systemModule9.js +++ b/tests/baselines/reference/systemModule9.js @@ -26,13 +26,12 @@ System.register(['file1', 'file2', 'file3', 'file4', 'file5', 'file6', 'file7'], var ns, file2_1, file3_1, file5_1, ns3; var x, y; var exportedNames_1 = { - 'x': void 0, - 'z': void 0 + 'x': true, + 'z': true }; - function exportStar_1(m, name) { + function exportStar_1(m) { for(var n in m) { - if (!exportedNames_1.hasOwnProperty(n)) exportedNames_1[n] = name; - if (exportedNames_1[n] === name) exports_1(n, m[n]); + if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, m[n]); } } return { @@ -54,7 +53,7 @@ System.register(['file1', 'file2', 'file3', 'file4', 'file5', 'file6', 'file7'], ns3 = _ns3; }, function (_file7_1) { - exportStar_1(_file7_1, 'file7'); + exportStar_1(_file7_1); }], execute: function() { ns.f(); diff --git a/tests/cases/compiler/systemModule11.ts b/tests/cases/compiler/systemModule11.ts index 9e27cc919ab..fb32af1e068 100644 --- a/tests/cases/compiler/systemModule11.ts +++ b/tests/cases/compiler/systemModule11.ts @@ -31,4 +31,9 @@ export function foo() {} var z, z1; export {z, z1 as z2}; -export {s, s1 as s2} from 'a' \ No newline at end of file +export {s, s1 as s2} from 'a' + +// @filename: file5.ts + +function foo() {} +export * from 'a'; \ No newline at end of file From 4a919d4f04a59216e5bd1e4866d07e85a014675a Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 29 Apr 2015 11:43:23 -0700 Subject: [PATCH 5/6] exclude 'default' from star exports --- src/compiler/emitter.ts | 13 +++++++------ .../baselines/reference/systemModule11.errors.txt | 6 ++++-- tests/baselines/reference/systemModule11.js | 14 ++++++++++---- tests/baselines/reference/systemModule9.js | 2 +- tests/cases/compiler/systemModule11.ts | 2 ++ 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 672a6b32126..e18054e7a4b 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -5047,11 +5047,11 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { writeLine(); write(` for(var n in m) {`); writeLine(); - write(` `); + write(` if (n !== "default"`); if (localNames) { - write(`if (!${localNames}.hasOwnProperty(n)) `); + write(`&& !${localNames}.hasOwnProperty(n)`); } - write(`${exportFunctionForFile}(n, m[n]);`); + write(`) ${exportFunctionForFile}(n, m[n]);`); writeLine(); write(" }"); writeLine(); @@ -5061,6 +5061,10 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { } function writeExportedName(node: Identifier | Declaration): void { + if (node.kind !== SyntaxKind.Identifier && node.flags & NodeFlags.Default) { + return; + } + if (started) { write(","); } @@ -5073,9 +5077,6 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { if (node.kind === SyntaxKind.Identifier) { emitNodeWithoutSourceMap(node); } - else if (node.flags & NodeFlags.Default) { - write("default"); - } else { emitDeclarationName(node); } diff --git a/tests/baselines/reference/systemModule11.errors.txt b/tests/baselines/reference/systemModule11.errors.txt index f45de9a7783..ed8f036c14f 100644 --- a/tests/baselines/reference/systemModule11.errors.txt +++ b/tests/baselines/reference/systemModule11.errors.txt @@ -1,8 +1,8 @@ tests/cases/compiler/file1.ts(7,15): error TS2307: Cannot find module 'bar'. tests/cases/compiler/file2.ts(7,15): error TS2307: Cannot find module 'bar'. tests/cases/compiler/file3.ts(2,25): error TS2307: Cannot find module 'a'. -tests/cases/compiler/file3.ts(3,15): error TS2307: Cannot find module 'bar'. -tests/cases/compiler/file4.ts(8,27): error TS2307: Cannot find module 'a'. +tests/cases/compiler/file3.ts(4,15): error TS2307: Cannot find module 'bar'. +tests/cases/compiler/file4.ts(9,27): error TS2307: Cannot find module 'a'. tests/cases/compiler/file5.ts(3,15): error TS2307: Cannot find module 'a'. @@ -33,6 +33,7 @@ tests/cases/compiler/file5.ts(3,15): error TS2307: Cannot find module 'a'. export {x, y as z} from 'a'; ~~~ !!! error TS2307: Cannot find module 'a'. + export default function foo() {} export * from 'bar'; ~~~~~ !!! error TS2307: Cannot find module 'bar'. @@ -41,6 +42,7 @@ tests/cases/compiler/file5.ts(3,15): error TS2307: Cannot find module 'a'. export var x; export function foo() {} + export default function (){} var z, z1; export {z, z1 as z2}; diff --git a/tests/baselines/reference/systemModule11.js b/tests/baselines/reference/systemModule11.js index 56c3125f553..91c05e8263a 100644 --- a/tests/baselines/reference/systemModule11.js +++ b/tests/baselines/reference/systemModule11.js @@ -21,12 +21,14 @@ export * from 'bar'; //// [file3.ts] export {x, y as z} from 'a'; +export default function foo() {} export * from 'bar'; //// [file4.ts] export var x; export function foo() {} +export default function (){} var z, z1; export {z, z1 as z2}; @@ -50,7 +52,7 @@ System.register(['bar'], function(exports_1) { }; function exportStar_1(m) { for(var n in m) { - if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, m[n]); + if (n !== "default"&& !exportedNames_1.hasOwnProperty(n)) exports_1(n, m[n]); } } return { @@ -72,7 +74,7 @@ System.register(['bar'], function(exports_1) { }; function exportStar_1(m) { for(var n in m) { - if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, m[n]); + if (n !== "default"&& !exportedNames_1.hasOwnProperty(n)) exports_1(n, m[n]); } } return { @@ -88,13 +90,15 @@ System.register(['bar'], function(exports_1) { }); //// [file3.js] System.register(['a', 'bar'], function(exports_1) { + function foo() { } + exports_1("default", foo); var exportedNames_1 = { 'x': true, 'z': true }; function exportStar_1(m) { for(var n in m) { - if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, m[n]); + if (n !== "default"&& !exportedNames_1.hasOwnProperty(n)) exports_1(n, m[n]); } } return { @@ -115,6 +119,8 @@ System.register(['a'], function(exports_1) { var x, z, z1; function foo() { } exports_1("foo", foo); + function default_1() { } + exports_1("default", default_1); return { setters:[ function (_a_1) { @@ -133,7 +139,7 @@ System.register(['a'], function(exports_1) { function foo() { } function exportStar_1(m) { for(var n in m) { - exports_1(n, m[n]); + if (n !== "default") exports_1(n, m[n]); } } return { diff --git a/tests/baselines/reference/systemModule9.js b/tests/baselines/reference/systemModule9.js index 2cc7bc68d73..af05948c351 100644 --- a/tests/baselines/reference/systemModule9.js +++ b/tests/baselines/reference/systemModule9.js @@ -31,7 +31,7 @@ System.register(['file1', 'file2', 'file3', 'file4', 'file5', 'file6', 'file7'], }; function exportStar_1(m) { for(var n in m) { - if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, m[n]); + if (n !== "default"&& !exportedNames_1.hasOwnProperty(n)) exports_1(n, m[n]); } } return { diff --git a/tests/cases/compiler/systemModule11.ts b/tests/cases/compiler/systemModule11.ts index fb32af1e068..28e88688f87 100644 --- a/tests/cases/compiler/systemModule11.ts +++ b/tests/cases/compiler/systemModule11.ts @@ -21,12 +21,14 @@ export * from 'bar'; // @filename: file3.ts export {x, y as z} from 'a'; +export default function foo() {} export * from 'bar'; // @filename: file4.ts export var x; export function foo() {} +export default function (){} var z, z1; export {z, z1 as z2}; From 2184be883c4818225360bcf7dd29139e7023ffa7 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 29 Apr 2015 13:56:17 -0700 Subject: [PATCH 6/6] addressed PR feedback --- src/compiler/emitter.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index e18054e7a4b..d18b91abb8b 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -5044,16 +5044,20 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { // define an export star helper function write(`function ${exportStarFunction}(m) {`); + increaseIndent(); writeLine(); - write(` for(var n in m) {`); + write(`for(var n in m) {`); + increaseIndent(); writeLine(); - write(` if (n !== "default"`); + write(`if (n !== "default"`); if (localNames) { write(`&& !${localNames}.hasOwnProperty(n)`); } write(`) ${exportFunctionForFile}(n, m[n]);`); + decreaseIndent(); writeLine(); - write(" }"); + write("}"); + decreaseIndent(); writeLine(); write("}") @@ -5061,6 +5065,8 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { } function writeExportedName(node: Identifier | Declaration): void { + // do not record default exports + // they are local to module and never overwritten (explicitly skipped) by star export if (node.kind !== SyntaxKind.Identifier && node.flags & NodeFlags.Default) { return; }