Skip to content

Commit bde81de

Browse files
dhruvrajvanshiAndy
authored andcommitted
Issue #27301: Fixed crash when converting function to async (#27396)
1 parent 19af881 commit bde81de

File tree

4 files changed

+88
-6
lines changed

4 files changed

+88
-6
lines changed

src/services/codefixes/convertToAsyncFunction.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,11 @@ namespace ts.codefix {
451451
}
452452

453453
return shouldReturn ? refactoredStmts.map(s => getSynthesizedDeepClone(s)) :
454-
removeReturns(refactoredStmts, prevArgName!.identifier, transformer, seenReturnStatement);
454+
removeReturns(
455+
refactoredStmts,
456+
prevArgName === undefined ? undefined : prevArgName.identifier,
457+
transformer,
458+
seenReturnStatement);
455459
}
456460
else {
457461
const innerRetStmts = getReturnStatementsWithPromiseHandlers(createReturn(funcBody));
@@ -491,14 +495,19 @@ namespace ts.codefix {
491495
}
492496

493497

494-
function removeReturns(stmts: ReadonlyArray<Statement>, prevArgName: Identifier, transformer: Transformer, seenReturnStatement: boolean): ReadonlyArray<Statement> {
498+
function removeReturns(stmts: ReadonlyArray<Statement>, prevArgName: Identifier | undefined, transformer: Transformer, seenReturnStatement: boolean): ReadonlyArray<Statement> {
495499
const ret: Statement[] = [];
496500
for (const stmt of stmts) {
497501
if (isReturnStatement(stmt)) {
498502
if (stmt.expression) {
499503
const possiblyAwaitedExpression = isPromiseReturningExpression(stmt.expression, transformer.checker) ? createAwait(stmt.expression) : stmt.expression;
500-
ret.push(createVariableStatement(/*modifiers*/ undefined,
501-
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, possiblyAwaitedExpression)], getFlagOfIdentifier(prevArgName, transformer.constIdentifiers)))));
504+
if (prevArgName === undefined) {
505+
ret.push(createExpressionStatement(possiblyAwaitedExpression));
506+
}
507+
else {
508+
ret.push(createVariableStatement(/*modifiers*/ undefined,
509+
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, possiblyAwaitedExpression)], getFlagOfIdentifier(prevArgName, transformer.constIdentifiers)))));
510+
}
502511
}
503512
}
504513
else {
@@ -507,7 +516,7 @@ namespace ts.codefix {
507516
}
508517

509518
// if block has no return statement, need to define prevArgName as undefined to prevent undeclared variables
510-
if (!seenReturnStatement) {
519+
if (!seenReturnStatement && prevArgName !== undefined) {
511520
ret.push(createVariableStatement(/*modifiers*/ undefined,
512521
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, createIdentifier("undefined"))], getFlagOfIdentifier(prevArgName, transformer.constIdentifiers)))));
513522
}

src/testRunner/unittests/convertToAsyncFunction.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,19 @@ _testConvertToAsyncFunction("convertToAsyncFunction_nestedPromises", `
12411241
function [#|f|]() {
12421242
return fetch('https://typescriptlang.org').then(x => Promise.resolve(3).then(y => Promise.resolve(x.statusText.length + y)));
12431243
}
1244+
`);
1245+
_testConvertToAsyncFunction("convertToAsyncFunction_noArgs", `
1246+
function delay(millis: number): Promise<void> {
1247+
throw "no"
1248+
}
1249+
1250+
function [#|main2|]() {
1251+
console.log("Please wait. Loading.");
1252+
return delay(500)
1253+
.then(() => { console.log("."); return delay(500); })
1254+
.then(() => { console.log("."); return delay(500); })
1255+
.then(() => { console.log("."); return delay(500); })
1256+
}
12441257
`);
12451258
});
12461259

@@ -1251,4 +1264,4 @@ function [#|f|]() {
12511264
function _testConvertToAsyncFunctionFailed(caption: string, text: string) {
12521265
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", /*includeLib*/ true, /*expectFailure*/ true);
12531266
}
1254-
}
1267+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// ==ORIGINAL==
2+
3+
function delay(millis) {
4+
throw "no"
5+
}
6+
7+
function /*[#|*/main2/*|]*/() {
8+
console.log("Please wait. Loading.");
9+
return delay(500)
10+
.then(() => { console.log("."); return delay(500); })
11+
.then(() => { console.log("."); return delay(500); })
12+
.then(() => { console.log("."); return delay(500); })
13+
}
14+
15+
// ==ASYNC FUNCTION::Convert to async function==
16+
17+
function delay(millis) {
18+
throw "no"
19+
}
20+
21+
async function main2() {
22+
console.log("Please wait. Loading.");
23+
await delay(500);
24+
console.log(".");
25+
await delay(500);
26+
console.log(".");
27+
await delay(500);
28+
console.log(".");
29+
return delay(500);
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// ==ORIGINAL==
2+
3+
function delay(millis: number): Promise<void> {
4+
throw "no"
5+
}
6+
7+
function /*[#|*/main2/*|]*/() {
8+
console.log("Please wait. Loading.");
9+
return delay(500)
10+
.then(() => { console.log("."); return delay(500); })
11+
.then(() => { console.log("."); return delay(500); })
12+
.then(() => { console.log("."); return delay(500); })
13+
}
14+
15+
// ==ASYNC FUNCTION::Convert to async function==
16+
17+
function delay(millis: number): Promise<void> {
18+
throw "no"
19+
}
20+
21+
async function main2() {
22+
console.log("Please wait. Loading.");
23+
await delay(500);
24+
console.log(".");
25+
await delay(500);
26+
console.log(".");
27+
await delay(500);
28+
console.log(".");
29+
return delay(500);
30+
}

0 commit comments

Comments
 (0)