Skip to content
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

Improve diagnostics for mismatched type in async main #3039

Closed
wants to merge 1 commit into from

Conversation

Aaron1011
Copy link
Contributor

Previously, we wrapped the body of the async main function in an
async block, which we passed to block_on. However, block_on is
generic, so an incorrect return type ends up creating a diagnostic
pointing a block_on, not the user's code. Since the call to block_on
is generated by the #[tokio::main] macro, it ended up with a span of
the #[tokio::main] attribute, producing a confusing diagnostic.

We now wrap the body of the async main function in a new
async main_inner function. This asserts a return type of () earlier
on, producing a diagnostic.

Given this code:

#[tokio::main]
async fn main() {
    Ok(())
}

We currently produce the error:

error[E0308]: mismatched types
 --> src/main.rs:1:1
  |
1 | #[tokio::main]
  | ^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
  | |
  | expected `()`, found enum `std::result::Result`
  |
  = note: expected unit type `()`
                  found enum `std::result::Result<(), _>`
  = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

With this PR, we produce:

error[E0308]: mismatched types
 --> src/main.rs:3:5
  |
3 |     Ok(())
  |     ^^^^^^- help: try adding a semicolon: `;`
  |     |
  |     expected `()`, found enum `std::result::Result`
  |
  = note: expected unit type `()`
                  found enum `std::result::Result<(), _>`

Tokio doesn't appear to have any kind of UI testing setup, so I'm not sure how to test the error message produced here.

Previously, we wrapped the body of the `async main` function in an
`async` block, which we passed to `block_on`. However, `block_on` is
generic, so an incorrect return type ends up creating a diagnostic
pointing a `block_on`, not the user's code. Since the call to `block_on`
is generated by the `#[tokio::main]` macro, it ended up with a span of
the `#[tokio::main]` attribute, producing a confusing diagnostic.

We now wrap the body of the `async main` function in a new
`async main_inner` function. This asserts a return type of `()` earlier
on, producing a diagnostic.

Given this code:

```rust
async fn main() {
    Ok(())
}
```

We currently produce the error:

```
error[E0308]: mismatched types
 --> src/main.rs:1:1
  |
1 | #[tokio::main]
  | ^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
  | |
  | expected `()`, found enum `std::result::Result`
  |
  = note: expected unit type `()`
                  found enum `std::result::Result<(), _>`
  = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
```

With this PR, we produce:

```
error[E0308]: mismatched types
 --> src/main.rs:3:5
  |
3 |     Ok(())
  |     ^^^^^^- help: try adding a semicolon: `;`
  |     |
  |     expected `()`, found enum `std::result::Result`
  |
  = note: expected unit type `()`
                  found enum `std::result::Result<(), _>`
```
@taiki-e taiki-e self-assigned this Oct 24, 2020
@taiki-e taiki-e added A-tokio-macros Area: The tokio-macros crate M-macros Module: macros in the main Tokio crate labels Oct 24, 2020
@Aaron1011
Copy link
Contributor Author

I didn't realize that tokio::main could be used on non-main fuctions, which may have generics. I'l have to see if there's a better way to get the desired diagnostic.

Copy link
Member

@taiki-e taiki-e left a comment

Choose a reason for hiding this comment

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

Thanks for the PR. Unfortunately, this approach (split an async fn to two async or normal fns) causes a breaking change because #[tokio::main] accepts arguments. The self argument can be handled in the same way as async-trait, but we know that some regressions occur. (see dtolnay/async-trait#122 (comment))

@taiki-e
Copy link
Member

taiki-e commented Oct 24, 2020

If macro generate code like the following, it should work.

    block_on(async {
        let res: #return_ty = #body;
        return res;
    })

(Note: If the return type contains impl trait, macro should omit the generation of : #return_ty)

@taiki-e taiki-e added the C-enhancement Category: A PR with an enhancement or bugfix. label Oct 24, 2020
@Darksonn
Copy link
Contributor

Darksonn commented May 5, 2021

@Aaron1011 Are you interested in continuing to work on this PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio-macros Area: The tokio-macros crate C-enhancement Category: A PR with an enhancement or bugfix. M-macros Module: macros in the main Tokio crate
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants