Skip to content

Improve diagnostics for mismatched type in async main#3039

Closed
Aaron1011 wants to merge 1 commit intotokio-rs:masterfrom
Aaron1011:improve/main-diag
Closed

Improve diagnostics for mismatched type in async main#3039
Aaron1011 wants to merge 1 commit intotokio-rs:masterfrom
Aaron1011:improve/main-diag

Conversation

@Aaron1011
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Member

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