Avoid emitting temp variable in downleveled import() (#51562)

This commit is contained in:
Joshua Chen 2022-11-20 01:22:41 -05:00 committed by GitHub
parent fa15877d63
commit df7f5fc94e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 63 additions and 51 deletions

View File

@ -958,32 +958,57 @@ export function transformModule(context: TransformationContext): (x: SourceFile
function createImportCallExpressionCommonJS(arg: Expression | undefined, isInlineable?: boolean): Expression {
// import(x)
// emit as
// var _a;
// (_a = x, Promise.resolve().then(() => require(_a)) /*CommonJs Require*/
// Promise.resolve(`${x}`).then((s) => require(s)) /*CommonJs Require*/
// We have to wrap require in then callback so that require is done in asynchronously
// if we simply do require in resolve callback in Promise constructor. We will execute the loading immediately
// If the arg is not inlineable, we have to evaluate it in the current scope with a temp var
const temp = arg && !isSimpleInlineableExpression(arg) && !isInlineable ? factory.createTempVariable(hoistVariableDeclaration) : undefined;
// If the arg is not inlineable, we have to evaluate and ToString() it in the current scope
// Otherwise, we inline it in require() so that it's statically analyzable
const needSyncEval = arg && !isSimpleInlineableExpression(arg) && !isInlineable;
const promiseResolveCall = factory.createCallExpression(
factory.createPropertyAccessExpression(factory.createIdentifier("Promise"), "resolve"),
/*typeArguments*/ undefined,
/*argumentsArray*/ [],
/*argumentsArray*/ needSyncEval
? languageVersion >= ScriptTarget.ES2015
? [
factory.createTemplateExpression(factory.createTemplateHead(""), [
factory.createTemplateSpan(arg, factory.createTemplateTail("")),
]),
]
: [
factory.createCallExpression(
factory.createPropertyAccessExpression(factory.createStringLiteral(""), "concat"),
/*typeArguments*/ undefined,
[arg]
),
]
: []
);
let requireCall: Expression = factory.createCallExpression(
factory.createIdentifier("require"),
/*typeArguments*/ undefined,
temp ? [temp] : arg ? [arg] : [],
needSyncEval ? [factory.createIdentifier("s")] : arg ? [arg] : [],
);
if (getESModuleInterop(compilerOptions)) {
requireCall = emitHelpers().createImportStarHelper(requireCall);
}
const parameters = needSyncEval
? [
factory.createParameterDeclaration(
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
/*name*/ "s"),
]
: [];
let func: FunctionExpression | ArrowFunction;
if (languageVersion >= ScriptTarget.ES2015) {
func = factory.createArrowFunction(
/*modifiers*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ [],
/*parameters*/ parameters,
/*type*/ undefined,
/*equalsGreaterThanToken*/ undefined,
requireCall);
@ -994,14 +1019,14 @@ export function transformModule(context: TransformationContext): (x: SourceFile
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ [],
/*parameters*/ parameters,
/*type*/ undefined,
factory.createBlock([factory.createReturnStatement(requireCall)]));
}
const downleveledImport = factory.createCallExpression(factory.createPropertyAccessExpression(promiseResolveCall, "then"), /*typeArguments*/ undefined, [func]);
return temp === undefined ? downleveledImport : factory.createCommaListExpression([factory.createAssignment(temp, arg!), downleveledImport]);
return downleveledImport;
}
function getHelperExpressionForExport(node: ExportDeclaration, innerExpr: Expression) {

View File

@ -46,13 +46,12 @@ var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _ar
function foo() {
return __asyncGenerator(this, arguments, function foo_1() {
return __generator(this, function (_a) {
var _b, _c;
switch (_a.label) {
case 0: return [4 /*yield*/, __await("foo")];
case 1: return [4 /*yield*/, _a.sent()];
case 2: return [4 /*yield*/, __await.apply(void 0, [(_b = _a.sent(), Promise.resolve().then(function () { return require(_b); }))])];
case 2: return [4 /*yield*/, __await.apply(void 0, [Promise.resolve("".concat(_a.sent())).then(function (s) { return require(s); })])];
case 3:
_c = (_a.sent())["default"], Promise.resolve().then(function () { return require(_c); });
Promise.resolve("".concat((_a.sent())["default"])).then(function (s) { return require(s); });
return [2 /*return*/];
}
});

View File

@ -16,16 +16,14 @@ const someFunction = async () => {
//// [dynamicImportEvaluateSpecifier.js]
var _a, _b;
// https://github.com/microsoft/TypeScript/issues/48285
let i = 0;
_a = String(i++), Promise.resolve().then(() => require(_a));
_b = String(i++), Promise.resolve().then(() => require(_b));
Promise.resolve(`${String(i++)}`).then(s => require(s));
Promise.resolve(`${String(i++)}`).then(s => require(s));
const getPath = async () => {
/* in reality this would do some async FS operation, or a web request */
return "/root/my/cool/path";
};
const someFunction = async () => {
var _a;
const result = await (_a = await getPath(), Promise.resolve().then(() => require(_a)));
const result = await Promise.resolve(`${await getPath()}`).then(s => require(s));
};

View File

@ -3,6 +3,5 @@ const path = './foo';
import(path,);
//// [dynamicImportTrailingComma.js]
var _a;
var path = './foo';
_a = path, Promise.resolve().then(function () { return require(_a); });
Promise.resolve("".concat(path)).then(function (s) { return require(s); });

View File

@ -15,14 +15,12 @@ function returnDynamicLoad(path: string) {
}
//// [importCallExpressionDeclarationEmit1.js]
var _a, _b, _c, _d;
_a = getSpecifier(), Promise.resolve().then(() => require(_a));
var p0 = (_b = `${directory}\\${moduleFile}`, Promise.resolve().then(() => require(_b)));
var p1 = (_c = getSpecifier(), Promise.resolve().then(() => require(_c)));
const p2 = (_d = whatToLoad ? getSpecifier() : "defaulPath", Promise.resolve().then(() => require(_d)));
Promise.resolve(`${getSpecifier()}`).then(s => require(s));
var p0 = Promise.resolve(`${`${directory}\\${moduleFile}`}`).then(s => require(s));
var p1 = Promise.resolve(`${getSpecifier()}`).then(s => require(s));
const p2 = Promise.resolve(`${whatToLoad ? getSpecifier() : "defaulPath"}`).then(s => require(s));
function returnDynamicLoad(path) {
var _a;
return _a = path, Promise.resolve().then(() => require(_a));
return Promise.resolve(`${path}`).then(s => require(s));
}

View File

@ -10,9 +10,8 @@ const p2 = import();
const p4 = import("pathToModule", "secondModule");
//// [importCallExpressionGrammarError.js]
var _a, _b;
var a = ["./0"];
_a = (...["PathModule"]), Promise.resolve().then(() => require(_a));
var p1 = (_b = (...a), Promise.resolve().then(() => require(_b)));
Promise.resolve(`${...["PathModule"]}`).then(s => require(s));
var p1 = Promise.resolve(`${...a}`).then(s => require(s));
const p2 = Promise.resolve().then(() => require());
const p4 = Promise.resolve().then(() => require("pathToModule"));

View File

@ -24,7 +24,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
};
function foo() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
return yield (_a = (yield Promise.resolve().then(() => require("./foo"))).default, Promise.resolve().then(() => require(_a)));
return yield Promise.resolve(`${(yield Promise.resolve().then(() => require("./foo"))).default}`).then(s => require(s));
});
}

View File

@ -52,10 +52,9 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
function foo() {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
var _b;
switch (_a.label) {
case 0: return [4 /*yield*/, Promise.resolve().then(function () { return require("./foo"); })];
case 1: return [4 /*yield*/, (_b = (_a.sent()).default, Promise.resolve().then(function () { return require(_b); }))];
case 1: return [4 /*yield*/, Promise.resolve("".concat((_a.sent()).default)).then(function (s) { return require(s); })];
case 2: return [2 /*return*/, _a.sent()];
}
});

View File

@ -42,23 +42,21 @@ class C {
exports.C = C;
//// [1.js]
"use strict";
var _a, _b, _c, _d, _e, _f, _g;
Object.defineProperty(exports, "__esModule", { value: true });
_a = `${directory}\\${moduleFile}`, Promise.resolve().then(() => require(_a));
_b = getSpecifier(), Promise.resolve().then(() => require(_b));
var p1 = (_c = ValidSomeCondition() ? "./0" : "externalModule", Promise.resolve().then(() => require(_c)));
var p1 = (_d = getSpecifier(), Promise.resolve().then(() => require(_d)));
var p11 = (_e = getSpecifier(), Promise.resolve().then(() => require(_e)));
const p2 = (_f = whatToLoad ? getSpecifier() : "defaulPath", Promise.resolve().then(() => require(_f)));
Promise.resolve(`${`${directory}\\${moduleFile}`}`).then(s => require(s));
Promise.resolve(`${getSpecifier()}`).then(s => require(s));
var p1 = Promise.resolve(`${ValidSomeCondition() ? "./0" : "externalModule"}`).then(s => require(s));
var p1 = Promise.resolve(`${getSpecifier()}`).then(s => require(s));
var p11 = Promise.resolve(`${getSpecifier()}`).then(s => require(s));
const p2 = Promise.resolve(`${whatToLoad ? getSpecifier() : "defaulPath"}`).then(s => require(s));
p1.then(zero => {
return zero.foo(); // ok, zero is any
});
let j;
var p3 = (_g = j = getSpecifier(), Promise.resolve().then(() => require(_g)));
var p3 = Promise.resolve(`${j = getSpecifier()}`).then(s => require(s));
function* loadModule(directories) {
var _a;
for (const directory of directories) {
const path = `${directory}\\moduleFile`;
_a = yield path, Promise.resolve().then(() => require(_a));
Promise.resolve(`${yield path}`).then(s => require(s));
}
}

View File

@ -14,13 +14,12 @@ var p3 = import(["path1", "path2"]);
var p4 = import(()=>"PathToModule");
//// [importCallExpressionSpecifierNotStringTypeError.js]
var _a, _b, _c, _d, _e;
// Error specifier is not assignable to string
_a = getSpecifier(), Promise.resolve().then(() => require(_a));
var p1 = (_b = getSpecifier(), Promise.resolve().then(() => require(_b)));
const p2 = (_c = whatToLoad ? getSpecifier() : "defaulPath", Promise.resolve().then(() => require(_c)));
Promise.resolve(`${getSpecifier()}`).then(s => require(s));
var p1 = Promise.resolve(`${getSpecifier()}`).then(s => require(s));
const p2 = Promise.resolve(`${whatToLoad ? getSpecifier() : "defaulPath"}`).then(s => require(s));
p1.then(zero => {
return zero.foo(); // ok, zero is any
});
var p3 = (_d = ["path1", "path2"], Promise.resolve().then(() => require(_d)));
var p4 = (_e = () => "PathToModule", Promise.resolve().then(() => require(_e)));
var p3 = Promise.resolve(`${["path1", "path2"]}`).then(s => require(s));
var p4 = Promise.resolve(`${() => "PathToModule"}`).then(s => require(s));

View File

@ -58,7 +58,6 @@ var v = import(String());
//// [jsdocInTypeScript.js]
var _a;
var T = /** @class */ (function () {
function T() {
}
@ -93,4 +92,4 @@ var E = {};
E[""];
// make sure import types in JSDoc are not resolved
/** @type {import("should-not-be-resolved").Type} */
var v = (_a = String(), Promise.resolve().then(function () { return require(_a); }));
var v = Promise.resolve("".concat(String())).then(function (s) { return require(s); });