Issue #27301: Fixed crash when converting function to async (#27396)

This commit is contained in:
Dhruv Rajvanshi 2018-09-28 07:26:37 +05:30 committed by Andy
parent 19af881f94
commit bde81deed2
4 changed files with 88 additions and 6 deletions

View file

@ -451,7 +451,11 @@ namespace ts.codefix {
}
return shouldReturn ? refactoredStmts.map(s => getSynthesizedDeepClone(s)) :
removeReturns(refactoredStmts, prevArgName!.identifier, transformer, seenReturnStatement);
removeReturns(
refactoredStmts,
prevArgName === undefined ? undefined : prevArgName.identifier,
transformer,
seenReturnStatement);
}
else {
const innerRetStmts = getReturnStatementsWithPromiseHandlers(createReturn(funcBody));
@ -491,14 +495,19 @@ namespace ts.codefix {
}
function removeReturns(stmts: ReadonlyArray<Statement>, prevArgName: Identifier, transformer: Transformer, seenReturnStatement: boolean): ReadonlyArray<Statement> {
function removeReturns(stmts: ReadonlyArray<Statement>, prevArgName: Identifier | undefined, transformer: Transformer, seenReturnStatement: boolean): ReadonlyArray<Statement> {
const ret: Statement[] = [];
for (const stmt of stmts) {
if (isReturnStatement(stmt)) {
if (stmt.expression) {
const possiblyAwaitedExpression = isPromiseReturningExpression(stmt.expression, transformer.checker) ? createAwait(stmt.expression) : stmt.expression;
ret.push(createVariableStatement(/*modifiers*/ undefined,
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, possiblyAwaitedExpression)], getFlagOfIdentifier(prevArgName, transformer.constIdentifiers)))));
if (prevArgName === undefined) {
ret.push(createExpressionStatement(possiblyAwaitedExpression));
}
else {
ret.push(createVariableStatement(/*modifiers*/ undefined,
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, possiblyAwaitedExpression)], getFlagOfIdentifier(prevArgName, transformer.constIdentifiers)))));
}
}
}
else {
@ -507,7 +516,7 @@ namespace ts.codefix {
}
// if block has no return statement, need to define prevArgName as undefined to prevent undeclared variables
if (!seenReturnStatement) {
if (!seenReturnStatement && prevArgName !== undefined) {
ret.push(createVariableStatement(/*modifiers*/ undefined,
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, createIdentifier("undefined"))], getFlagOfIdentifier(prevArgName, transformer.constIdentifiers)))));
}

View file

@ -1241,6 +1241,19 @@ _testConvertToAsyncFunction("convertToAsyncFunction_nestedPromises", `
function [#|f|]() {
return fetch('https://typescriptlang.org').then(x => Promise.resolve(3).then(y => Promise.resolve(x.statusText.length + y)));
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_noArgs", `
function delay(millis: number): Promise<void> {
throw "no"
}
function [#|main2|]() {
console.log("Please wait. Loading.");
return delay(500)
.then(() => { console.log("."); return delay(500); })
.then(() => { console.log("."); return delay(500); })
.then(() => { console.log("."); return delay(500); })
}
`);
});
@ -1251,4 +1264,4 @@ function [#|f|]() {
function _testConvertToAsyncFunctionFailed(caption: string, text: string) {
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", /*includeLib*/ true, /*expectFailure*/ true);
}
}
}

View file

@ -0,0 +1,30 @@
// ==ORIGINAL==
function delay(millis) {
throw "no"
}
function /*[#|*/main2/*|]*/() {
console.log("Please wait. Loading.");
return delay(500)
.then(() => { console.log("."); return delay(500); })
.then(() => { console.log("."); return delay(500); })
.then(() => { console.log("."); return delay(500); })
}
// ==ASYNC FUNCTION::Convert to async function==
function delay(millis) {
throw "no"
}
async function main2() {
console.log("Please wait. Loading.");
await delay(500);
console.log(".");
await delay(500);
console.log(".");
await delay(500);
console.log(".");
return delay(500);
}

View file

@ -0,0 +1,30 @@
// ==ORIGINAL==
function delay(millis: number): Promise<void> {
throw "no"
}
function /*[#|*/main2/*|]*/() {
console.log("Please wait. Loading.");
return delay(500)
.then(() => { console.log("."); return delay(500); })
.then(() => { console.log("."); return delay(500); })
.then(() => { console.log("."); return delay(500); })
}
// ==ASYNC FUNCTION::Convert to async function==
function delay(millis: number): Promise<void> {
throw "no"
}
async function main2() {
console.log("Please wait. Loading.");
await delay(500);
console.log(".");
await delay(500);
console.log(".");
await delay(500);
console.log(".");
return delay(500);
}