Skip to content

Commit a667884

Browse files
committed
Avoid emitting temp variable in downleveled import()
1 parent e99c935 commit a667884

11 files changed

+63
-51
lines changed

src/compiler/transformers/module/module.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -850,32 +850,57 @@ export function transformModule(context: TransformationContext): (x: SourceFile
850850
function createImportCallExpressionCommonJS(arg: Expression | undefined, isInlineable?: boolean): Expression {
851851
// import(x)
852852
// emit as
853-
// var _a;
854-
// (_a = x, Promise.resolve().then(() => require(_a)) /*CommonJs Require*/
853+
// Promise.resolve(`${x}`).then((s) => require(s)) /*CommonJs Require*/
855854
// We have to wrap require in then callback so that require is done in asynchronously
856855
// if we simply do require in resolve callback in Promise constructor. We will execute the loading immediately
857-
// If the arg is not inlineable, we have to evaluate it in the current scope with a temp var
858-
const temp = arg && !isSimpleInlineableExpression(arg) && !isInlineable ? factory.createTempVariable(hoistVariableDeclaration) : undefined;
856+
// If the arg is not inlineable, we have to evaluate and ToString() it in the current scope
857+
// Otherwise, we inline it in require() so that it's statically analyzable
858+
const needSyncEval = arg && !isSimpleInlineableExpression(arg) && !isInlineable;
859+
859860
const promiseResolveCall = factory.createCallExpression(
860861
factory.createPropertyAccessExpression(factory.createIdentifier("Promise"), "resolve"),
861862
/*typeArguments*/ undefined,
862-
/*argumentsArray*/ [],
863+
/*argumentsArray*/ needSyncEval
864+
? languageVersion >= ScriptTarget.ES2015
865+
? [
866+
factory.createTemplateExpression(factory.createTemplateHead(""), [
867+
factory.createTemplateSpan(arg, factory.createTemplateTail("")),
868+
]),
869+
]
870+
: [
871+
factory.createCallExpression(
872+
factory.createPropertyAccessExpression(factory.createStringLiteral(""), "concat"),
873+
/*typeArguments*/ undefined,
874+
[arg]
875+
),
876+
]
877+
: []
863878
);
879+
864880
let requireCall: Expression = factory.createCallExpression(
865881
factory.createIdentifier("require"),
866882
/*typeArguments*/ undefined,
867-
temp ? [temp] : arg ? [arg] : [],
883+
needSyncEval ? [factory.createIdentifier("s")] : arg ? [arg] : [],
868884
);
869885
if (getESModuleInterop(compilerOptions)) {
870886
requireCall = emitHelpers().createImportStarHelper(requireCall);
871887
}
872888

889+
const parameters = needSyncEval
890+
? [
891+
factory.createParameterDeclaration(
892+
/*modifiers*/ undefined,
893+
/*dotDotDotToken*/ undefined,
894+
/*name*/ "s"),
895+
]
896+
: [];
897+
873898
let func: FunctionExpression | ArrowFunction;
874899
if (languageVersion >= ScriptTarget.ES2015) {
875900
func = factory.createArrowFunction(
876901
/*modifiers*/ undefined,
877902
/*typeParameters*/ undefined,
878-
/*parameters*/ [],
903+
/*parameters*/ parameters,
879904
/*type*/ undefined,
880905
/*equalsGreaterThanToken*/ undefined,
881906
requireCall);
@@ -886,14 +911,14 @@ export function transformModule(context: TransformationContext): (x: SourceFile
886911
/*asteriskToken*/ undefined,
887912
/*name*/ undefined,
888913
/*typeParameters*/ undefined,
889-
/*parameters*/ [],
914+
/*parameters*/ parameters,
890915
/*type*/ undefined,
891916
factory.createBlock([factory.createReturnStatement(requireCall)]));
892917
}
893918

894919
const downleveledImport = factory.createCallExpression(factory.createPropertyAccessExpression(promiseResolveCall, "then"), /*typeArguments*/ undefined, [func]);
895920

896-
return temp === undefined ? downleveledImport : factory.createCommaListExpression([factory.createAssignment(temp, arg!), downleveledImport]);
921+
return downleveledImport;
897922
}
898923

899924
function getHelperExpressionForExport(node: ExportDeclaration, innerExpr: Expression) {

tests/baselines/reference/asyncImportNestedYield.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,12 @@ var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _ar
4646
function foo() {
4747
return __asyncGenerator(this, arguments, function foo_1() {
4848
return __generator(this, function (_a) {
49-
var _b, _c;
5049
switch (_a.label) {
5150
case 0: return [4 /*yield*/, __await("foo")];
5251
case 1: return [4 /*yield*/, _a.sent()];
53-
case 2: return [4 /*yield*/, __await.apply(void 0, [(_b = _a.sent(), Promise.resolve().then(function () { return require(_b); }))])];
52+
case 2: return [4 /*yield*/, __await.apply(void 0, [Promise.resolve("".concat(_a.sent())).then(function (s) { return require(s); })])];
5453
case 3:
55-
_c = (_a.sent())["default"], Promise.resolve().then(function () { return require(_c); });
54+
Promise.resolve("".concat((_a.sent())["default"])).then(function (s) { return require(s); });
5655
return [2 /*return*/];
5756
}
5857
});

tests/baselines/reference/dynamicImportEvaluateSpecifier.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,14 @@ const someFunction = async () => {
1616

1717

1818
//// [dynamicImportEvaluateSpecifier.js]
19-
var _a, _b;
2019
// https://github.com/microsoft/TypeScript/issues/48285
2120
let i = 0;
22-
_a = String(i++), Promise.resolve().then(() => require(_a));
23-
_b = String(i++), Promise.resolve().then(() => require(_b));
21+
Promise.resolve(`${String(i++)}`).then(s => require(s));
22+
Promise.resolve(`${String(i++)}`).then(s => require(s));
2423
const getPath = async () => {
2524
/* in reality this would do some async FS operation, or a web request */
2625
return "/root/my/cool/path";
2726
};
2827
const someFunction = async () => {
29-
var _a;
30-
const result = await (_a = await getPath(), Promise.resolve().then(() => require(_a)));
28+
const result = await Promise.resolve(`${await getPath()}`).then(s => require(s));
3129
};

tests/baselines/reference/dynamicImportTrailingComma.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,5 @@ const path = './foo';
33
import(path,);
44

55
//// [dynamicImportTrailingComma.js]
6-
var _a;
76
var path = './foo';
8-
_a = path, Promise.resolve().then(function () { return require(_a); });
7+
Promise.resolve("".concat(path)).then(function (s) { return require(s); });

tests/baselines/reference/importCallExpressionDeclarationEmit1.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,12 @@ function returnDynamicLoad(path: string) {
1515
}
1616

1717
//// [importCallExpressionDeclarationEmit1.js]
18-
var _a, _b, _c, _d;
19-
_a = getSpecifier(), Promise.resolve().then(() => require(_a));
20-
var p0 = (_b = `${directory}\\${moduleFile}`, Promise.resolve().then(() => require(_b)));
21-
var p1 = (_c = getSpecifier(), Promise.resolve().then(() => require(_c)));
22-
const p2 = (_d = whatToLoad ? getSpecifier() : "defaulPath", Promise.resolve().then(() => require(_d)));
18+
Promise.resolve(`${getSpecifier()}`).then(s => require(s));
19+
var p0 = Promise.resolve(`${`${directory}\\${moduleFile}`}`).then(s => require(s));
20+
var p1 = Promise.resolve(`${getSpecifier()}`).then(s => require(s));
21+
const p2 = Promise.resolve(`${whatToLoad ? getSpecifier() : "defaulPath"}`).then(s => require(s));
2322
function returnDynamicLoad(path) {
24-
var _a;
25-
return _a = path, Promise.resolve().then(() => require(_a));
23+
return Promise.resolve(`${path}`).then(s => require(s));
2624
}
2725

2826

tests/baselines/reference/importCallExpressionGrammarError.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ const p2 = import();
1010
const p4 = import("pathToModule", "secondModule");
1111

1212
//// [importCallExpressionGrammarError.js]
13-
var _a, _b;
1413
var a = ["./0"];
15-
_a = (...["PathModule"]), Promise.resolve().then(() => require(_a));
16-
var p1 = (_b = (...a), Promise.resolve().then(() => require(_b)));
14+
Promise.resolve(`${...["PathModule"]}`).then(s => require(s));
15+
var p1 = Promise.resolve(`${...a}`).then(s => require(s));
1716
const p2 = Promise.resolve().then(() => require());
1817
const p4 = Promise.resolve().then(() => require("pathToModule"));

tests/baselines/reference/importCallExpressionNestedCJS.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
2424
};
2525
function foo() {
2626
return __awaiter(this, void 0, void 0, function* () {
27-
var _a;
28-
return yield (_a = (yield Promise.resolve().then(() => require("./foo"))).default, Promise.resolve().then(() => require(_a)));
27+
return yield Promise.resolve(`${(yield Promise.resolve().then(() => require("./foo"))).default}`).then(s => require(s));
2928
});
3029
}

tests/baselines/reference/importCallExpressionNestedCJS2.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,9 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
5252
function foo() {
5353
return __awaiter(this, void 0, void 0, function () {
5454
return __generator(this, function (_a) {
55-
var _b;
5655
switch (_a.label) {
5756
case 0: return [4 /*yield*/, Promise.resolve().then(function () { return require("./foo"); })];
58-
case 1: return [4 /*yield*/, (_b = (_a.sent()).default, Promise.resolve().then(function () { return require(_b); }))];
57+
case 1: return [4 /*yield*/, Promise.resolve("".concat((_a.sent()).default)).then(function (s) { return require(s); })];
5958
case 2: return [2 /*return*/, _a.sent()];
6059
}
6160
});

tests/baselines/reference/importCallExpressionReturnPromiseOfAny.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,21 @@ class C {
4242
exports.C = C;
4343
//// [1.js]
4444
"use strict";
45-
var _a, _b, _c, _d, _e, _f, _g;
4645
Object.defineProperty(exports, "__esModule", { value: true });
47-
_a = `${directory}\\${moduleFile}`, Promise.resolve().then(() => require(_a));
48-
_b = getSpecifier(), Promise.resolve().then(() => require(_b));
49-
var p1 = (_c = ValidSomeCondition() ? "./0" : "externalModule", Promise.resolve().then(() => require(_c)));
50-
var p1 = (_d = getSpecifier(), Promise.resolve().then(() => require(_d)));
51-
var p11 = (_e = getSpecifier(), Promise.resolve().then(() => require(_e)));
52-
const p2 = (_f = whatToLoad ? getSpecifier() : "defaulPath", Promise.resolve().then(() => require(_f)));
46+
Promise.resolve(`${`${directory}\\${moduleFile}`}`).then(s => require(s));
47+
Promise.resolve(`${getSpecifier()}`).then(s => require(s));
48+
var p1 = Promise.resolve(`${ValidSomeCondition() ? "./0" : "externalModule"}`).then(s => require(s));
49+
var p1 = Promise.resolve(`${getSpecifier()}`).then(s => require(s));
50+
var p11 = Promise.resolve(`${getSpecifier()}`).then(s => require(s));
51+
const p2 = Promise.resolve(`${whatToLoad ? getSpecifier() : "defaulPath"}`).then(s => require(s));
5352
p1.then(zero => {
5453
return zero.foo(); // ok, zero is any
5554
});
5655
let j;
57-
var p3 = (_g = j = getSpecifier(), Promise.resolve().then(() => require(_g)));
56+
var p3 = Promise.resolve(`${j = getSpecifier()}`).then(s => require(s));
5857
function* loadModule(directories) {
59-
var _a;
6058
for (const directory of directories) {
6159
const path = `${directory}\\moduleFile`;
62-
_a = yield path, Promise.resolve().then(() => require(_a));
60+
Promise.resolve(`${yield path}`).then(s => require(s));
6361
}
6462
}

tests/baselines/reference/importCallExpressionSpecifierNotStringTypeError.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,12 @@ var p3 = import(["path1", "path2"]);
1414
var p4 = import(()=>"PathToModule");
1515

1616
//// [importCallExpressionSpecifierNotStringTypeError.js]
17-
var _a, _b, _c, _d, _e;
1817
// Error specifier is not assignable to string
19-
_a = getSpecifier(), Promise.resolve().then(() => require(_a));
20-
var p1 = (_b = getSpecifier(), Promise.resolve().then(() => require(_b)));
21-
const p2 = (_c = whatToLoad ? getSpecifier() : "defaulPath", Promise.resolve().then(() => require(_c)));
18+
Promise.resolve(`${getSpecifier()}`).then(s => require(s));
19+
var p1 = Promise.resolve(`${getSpecifier()}`).then(s => require(s));
20+
const p2 = Promise.resolve(`${whatToLoad ? getSpecifier() : "defaulPath"}`).then(s => require(s));
2221
p1.then(zero => {
2322
return zero.foo(); // ok, zero is any
2423
});
25-
var p3 = (_d = ["path1", "path2"], Promise.resolve().then(() => require(_d)));
26-
var p4 = (_e = () => "PathToModule", Promise.resolve().then(() => require(_e)));
24+
var p3 = Promise.resolve(`${["path1", "path2"]}`).then(s => require(s));
25+
var p4 = Promise.resolve(`${() => "PathToModule"}`).then(s => require(s));

0 commit comments

Comments
 (0)