Skip to content

fix(39589): await is missing after autofix convert to an async function #39649

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 22, 2020

Conversation

a-tarasyuk
Copy link
Contributor

@a-tarasyuk a-tarasyuk commented Jul 18, 2020

Fixes #39589

@typescript-bot typescript-bot added the For Backlog Bug PRs that fix a backlog bug label Jul 21, 2020
@@ -26,5 +26,6 @@ async function main2() {
console.log(".");
await delay(500);
console.log(".");
return delay(500);
return await delay(500);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could be wrong, but I believe we only need this change if the statement is inside a try block. Does that seem right, and do you think it would be difficult to limit the change to just those cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean for the following code the need to omit await in return statement and add it only if if inside try block?

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); })
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, only if the resulting generated code is inside a try. return await is usually regarded as poor style, kind of like returning Promise.resolve(something) in a then. But it has importantly different semantics when inside a try block because it makes the difference between the error being handled in the function implementation vs. propagating the rejection onto the caller.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example:

async function f1() {
  return await fetch('/'); // `await` is not useful here
}

async function f2() {
  try {
    // `await` is useful here; without it, the catch block would never execute.
    // f2 returns a Promise that never rejects. f1 returns a Promise that resolves
    // or rejects with `fetch('/')`, with or without the `await`.
    return await fetch('/');
  } catch {
    return {};
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrewbranch Should these examples also omit await in return?

const x = await fetch('https://typescriptlang.org');
const y = await Promise.resolve(3);
return await Promise.resolve(x.statusText.length + y);

or

async function f() {
const s = await fetch('https://typescriptlang.org');
return await Promise.resolve(s.statusText.length);

I'm thinking about how to handle await inside/outside try statement. Maybe you have some thoughts about that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that baseline pointed me to this PR: #27573

I guess this is already a known limitation of the refactor. In that case, I’m ok with your PR as-is.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I’m a little confused as to why #27573 didn’t already apply to some of the baselines that changed in this PR. I do think that if we start adding a lot more return await, people are going to file issues about it. 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrewbranch Thanks for sharing this PR. I didn't know about it.

Copy link
Contributor Author

@a-tarasyuk a-tarasyuk Sep 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, this PR fixes a really simple issue, it just handles return statements in {}. For instance, two examples with the same logic behave differently. Example

function fn(): Promise<void> {
    return Promise.resolve();
}

// Before
function f1() {
    return fn().then(() => fn());
}
// After 
async function f1() {
    await fn();
return await fn(); // await is added
}

// Before
function f2() {
    return fn().then(() => { return fn() });
}
// After 
async function f2() {
    await fn();
return fn(); // await is missing 
}

About for the test, there is a test for {}, however, there is no test for (). I decided to add, to handle both cases. https://github.com/microsoft/TypeScript/pull/39649/files#diff-71c285c7a401ed150a7e8367a2d6681cR1408-R1422

@a-tarasyuk a-tarasyuk marked this pull request as draft September 11, 2020 13:58
@a-tarasyuk a-tarasyuk marked this pull request as ready for review September 11, 2020 19:46
Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m a little nervous that people will notice more unnecessary return await and complain, but this does solve a pretty bad correctness bug, and it sounds like we have an exact precedent for adding return await in exchange for correctness. We’ll let user feedback drive whether we need to address return await more broadly in the future.

@andrewbranch andrewbranch merged commit c5a28fc into microsoft:master Sep 22, 2020
@andrewbranch
Copy link
Member

Thanks @a-tarasyuk!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Backlog Bug PRs that fix a backlog bug
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

await is missing after autofix convert to an async function
3 participants