Skip to content

Commit df7f5fc

Browse files
authored
Avoid emitting temp variable in downleveled import() (#51562)
1 parent fa15877 commit df7f5fc

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
@@ -958,32 +958,57 @@ export function transformModule(context: TransformationContext): (x: SourceFile
958958
function createImportCallExpressionCommonJS(arg: Expression | undefined, isInlineable?: boolean): Expression {
959959
// import(x)
960960
// emit as
961-
// var _a;
962-
// (_a = x, Promise.resolve().then(() => require(_a)) /*CommonJs Require*/
961+
// Promise.resolve(`${x}`).then((s) => require(s)) /*CommonJs Require*/
963962
// We have to wrap require in then callback so that require is done in asynchronously
964963
// if we simply do require in resolve callback in Promise constructor. We will execute the loading immediately
965-
// If the arg is not inlineable, we have to evaluate it in the current scope with a temp var
966-
const temp = arg && !isSimpleInlineableExpression(arg) && !isInlineable ? factory.createTempVariable(hoistVariableDeclaration) : undefined;
964+
// If the arg is not inlineable, we have to evaluate and ToString() it in the current scope
965+
// Otherwise, we inline it in require() so that it's statically analyzable
966+
const needSyncEval = arg && !isSimpleInlineableExpression(arg) && !isInlineable;
967+
967968
const promiseResolveCall = factory.createCallExpression(
968969
factory.createPropertyAccessExpression(factory.createIdentifier("Promise"), "resolve"),
969970
/*typeArguments*/ undefined,
970-
/*argumentsArray*/ [],
971+
/*argumentsArray*/ needSyncEval
972+
? languageVersion >= ScriptTarget.ES2015
973+
? [
974+
factory.createTemplateExpression(factory.createTemplateHead(""), [
975+
factory.createTemplateSpan(arg, factory.createTemplateTail("")),
976+
]),
977+
]
978+
: [
979+
factory.createCallExpression(
980+
factory.createPropertyAccessExpression(factory.createStringLiteral(""), "concat"),
981+
/*typeArguments*/ undefined,
982+
[arg]
983+
),
984+
]
985+
: []
971986
);
987+
972988
let requireCall: Expression = factory.createCallExpression(
973989
factory.createIdentifier("require"),
974990
/*typeArguments*/ undefined,
975-
temp ? [temp] : arg ? [arg] : [],
991+
needSyncEval ? [factory.createIdentifier("s")] : arg ? [arg] : [],
976992
);
977993
if (getESModuleInterop(compilerOptions)) {
978994
requireCall = emitHelpers().createImportStarHelper(requireCall);
979995
}
980996

997+
const parameters = needSyncEval
998+
? [
999+
factory.createParameterDeclaration(
1000+
/*modifiers*/ undefined,
1001+
/*dotDotDotToken*/ undefined,
1002+
/*name*/ "s"),
1003+
]
1004+
: [];
1005+
9811006
let func: FunctionExpression | ArrowFunction;
9821007
if (languageVersion >= ScriptTarget.ES2015) {
9831008
func = factory.createArrowFunction(
9841009
/*modifiers*/ undefined,
9851010
/*typeParameters*/ undefined,
986-
/*parameters*/ [],
1011+
/*parameters*/ parameters,
9871012
/*type*/ undefined,
9881013
/*equalsGreaterThanToken*/ undefined,
9891014
requireCall);
@@ -994,14 +1019,14 @@ export function transformModule(context: TransformationContext): (x: SourceFile
9941019
/*asteriskToken*/ undefined,
9951020
/*name*/ undefined,
9961021
/*typeParameters*/ undefined,
997-
/*parameters*/ [],
1022+
/*parameters*/ parameters,
9981023
/*type*/ undefined,
9991024
factory.createBlock([factory.createReturnStatement(requireCall)]));
10001025
}
10011026

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

1004-
return temp === undefined ? downleveledImport : factory.createCommaListExpression([factory.createAssignment(temp, arg!), downleveledImport]);
1029+
return downleveledImport;
10051030
}
10061031

10071032
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)